题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=2002
题解:
LCT
如果把弹跳的起点和终点连一条边,弹出去的与n+1号点连边,
则不难发现,整个图形成了一颗树,
同时需要支持树的修改(拆分,合并)和询问点的深度(该点到根的链上的点的个数),
所以LCT可以很轻松的解决本题。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #define MAXN 200050 using namespace std; int N,M,next[MAXN]; struct LCT{ int ch[MAXN][2],fa[MAXN],rev[MAXN],size[MAXN]; bool Which(int x){return ch[fa[x]][1]==x;} void Reverse(int x){swap(ch[x][0],ch[x][1]);rev[x]^=1;} bool Isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} void Pushup(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+1;} void Pushdown(int x){ if(!Isroot(x)) Pushdown(fa[x]); if(rev[x]) Reverse(ch[x][0]),Reverse(ch[x][1]),rev[x]^=1; } void Rotate(int x){ static int y,z,l1,l2; y=fa[x]; z=fa[y]; l1=Which(y); l2=Which(x); fa[x]=z; if(!Isroot(y)) ch[z][l1]=x; fa[y]=x; fa[ch[x][l2^1]]=y; ch[y][l2]=ch[x][l2^1]; ch[x][l2^1]=y; Pushup(y); } void Splay(int x){ static int y; Pushdown(x); for(;y=fa[x],!Isroot(x);Rotate(x)) if(!Isroot(y)) Rotate(Which(y)==Which(x)?y:x); Pushup(x); } void Access(int x){ static int y; for(y=0;x;y=x,x=fa[x]) Splay(x),ch[x][1]=y,Pushup(x);//!!! } void Beroot(int x){ Access(x); Splay(x); Reverse(x); } void Cut(int x,int y){ Beroot(x); Access(y); Splay(y); fa[x]=ch[y][0]=0; Pushup(y); } void Link(int x,int y){ Beroot(x); fa[x]=y; } void Modify(int x,int k){ static int t; t=min(x+k,N+1); Cut(next[x],x); Link(t,x); next[x]=t; } int Query(int x){ Beroot(N+1); Access(x); Splay(x); return size[x]-1; } }DT; int main(){ scanf("%d",&N); DT.size[N+1]=1; for(int i=1,k;i<=N;i++){ scanf("%d",&k); next[i]=min(i+k,N+1); DT.fa[i]=next[i]; DT.size[i]=1; } scanf("%d",&M); int a,b,c; for(int i=1;i<=M;i++){ scanf("%d%d",&a,&b); b++; if(a==1) printf("%d ",DT.Query(b)); else scanf("%d",&c),DT.Modify(b,c); } return 0; }