P3203 [HNOI2010] 弹飞绵羊
题目描述
某天,Lostmonkey 发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。
游戏一开始,Lostmonkey 在地上沿着一条直线摆上 \(n\) 个装置,每个装置设定初始弹力系数 \(k_i\),当绵羊达到第 \(i\) 个装置时,它会往后弹 \(k_i\) 步,达到第 \(i+k_i\) 个装置,若不存在第 \(i+k_i\) 个装置,则绵羊被弹飞。
绵羊想知道当它从第 \(i\) 个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey 可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
输入格式
第一行包含一个整数 \(n\),表示地上有 \(n\) 个装置,装置的编号从 \(0 \sim n-1\)。
接下来一行有 \(n\) 个正整数,依次为那 \(n\) 个装置的初始弹力系数。
第三行有一个正整数 \(m\),表示操作次数。接下来 \(m\) 行每行至少有两个数 \(i,j\)。
-
若 \(i=1\),你要输出从编号为 \(j\) 的装置出发被弹几次后被弹飞
-
若 \(i=2\),则还会再输入一个正整数 \(k\),表示编号为 \(j\) 的弹力装置的系数被修改成 \(k\)。
输出格式
对于每个 \(i=1\) 的操作,输出一行一个整数表示答案。
【数据范围】
对于 \(100\%\) 的数据,\(1\le n \le 2\times 10^5\),\(1\le m \le 10^5\)。
Solution:
LD再不放假让你飞起来
没想到这种题目还能用 LCT 做。我们思考一下每次重设弹力系数相当于什么:相当于断掉原来的边然后连一条 (x,x+k) 的边。所以我们开始时将每个点到对应的“着陆点”上就好了,然后注意一下因为弹飞显然是单向的,所有我们只需要让 \(x\) 认父就好了,并不需要像原来的 link 一样。然后查询就直接 access 然后 splay 就好了。我们甚至都不需要换根(显然,因为没有查询两个点的路径的需求)。
然后这道看起来很模拟的 LCT 就被我们愉快的做完了。
Code:
#include<bits/stdc++.h>
const int N=2e5+5;
using namespace std;
int n,m;
struct LCT{struct Tree{int tag,ff,ch[2],siz;}t[N<<2];int st[N];#define ls t[x].ch[0]#define rs t[x].ch[1]#define fa t[x].ffinline bool isroot(int x){return (t[fa].ch[0]==x||t[fa].ch[1]==x);}inline void pushup(int x){t[x].siz=t[ls].siz+t[rs].siz+1;}inline void rotate(int x){int y=fa,z=t[fa].ff,k=t[fa].ch[1]==x ? 1 : 0;if(isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;t[y].ch[k]=t[x].ch[!k];if(t[x].ch[!k])t[t[x].ch[!k]].ff=y;t[x].ch[!k]=y;t[y].ff=x;pushup(y);}inline void splay(int x){int y=x,z=0;while(isroot(x)){y=fa,z=t[fa].ff;if(isroot(y)){rotate((t[y].ch[1]==x)==(t[z].ch[1]==y) ? y : x);}rotate(x);}pushup(x);}void access(int x){int y=0;while(x){splay(x);rs=y;pushup(x);y=x;x=fa;}}void link(int x,int y){if(y<=n){t[x].ff=y;pushup(x);}}void cut(int x) // 这里是减去一个点 x{access(x),splay(x);t[x].ch[0]=t[ls].ff=0;}int query(int x){access(x);splay(x);return t[x].siz;}
}T;
void work()
{cin>>n;for(int i=1,tmp;i<=n;i++){scanf("%d",&tmp);T.t[i].siz=1;T.link(i,i+tmp);}cin>>m;for(int i=1,opt,x,y;i<=m;i++){scanf("%d%d",&opt,&x);x++;if(opt&1){int ans=T.query(x);printf("%d\n",ans);}else{scanf("%d",&y);T.cut(x);T.link(x,x+y);}}
}
int main()
{//freopen("bounce.in","r",stdin);freopen("bounce.out","w",stdout);work();return 0;
}