BZOJ2002 HNOI2010 Bounce 弹飞绵羊 LCT
题意:给定一个长度为N的数列,每个元素有一个权值w[i],表示从i出发能到i+w[i],如果结果大于N则结束,维护:1、从i出发能转移多少次 2、修改w[i]
题解:建树,在i(儿子)和i+w[i](父亲)之间连边,大于N直接连到虚根上,每次询问直接查找i到根节点路径上的点数。因为边的连接情况是动态的,所以用LCT维护
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=200000+2; typedef struct NODE{ int c; NODE *f,*child[2]; } *TREE; TREE mark[MAXN],Null; int N,M; TREE NewNode(TREE f){ TREE x=new NODE; x->f=f,x->c=1; x->child[0]=x->child[1]=Null; return x; } void Initialise(int N){ Null=NewNode(0),Null->c=0; for(int i=1;i<=N;i++) mark[i]=NewNode(Null); } void Pushup(TREE &x){ x->c=x->child[0]->c+x->child[1]->c+1;} void Rotate(TREE &x,bool t){ TREE y=x->f; y->child[!t]=x->child[t],x->child[t]->f=y,x->f=y->f; if(y->f->child[0]==y) y->f->child[0]=x; else if(y->f->child[1]==y) y->f->child[1]=x; y->f=x,x->child[t]=y; Pushup(y),Pushup(x); } void Splay(TREE &x){ while(x->f->child[0]==x || x->f->child[1]==x){ TREE y=x->f; if(x==y->child[0]){ if(y==y->f->child[0]) Rotate(y,1); Rotate(x,1); } else{ if(y==y->f->child[1]) Rotate(y,0); Rotate(x,0); } } } void Access(TREE &x){ TREE y=Null,z=x; while(x!=Null){ Splay(x); x->child[1]=y; Pushup(x); y=x,x=x->f; } x=z; } void Link(TREE &x,TREE &y){ Access(x),Splay(x); x->child[0]->f=Null,x->child[0]=Null; x->f=y; Pushup(x); } int main(){ cin >> N; Initialise(N); for(int i=1,d;i<=N;i++){ cin >> d; if(i+d<=N) mark[i]->f=mark[i+d]; } cin >> M; for(int i=1,a,b,d;i<=M;i++){ cin >> a >> b,b++; if(a==1){ Access(mark[b]),Splay(mark[b]); cout << mark[b]->c << endl; } else{ cin >> d; if(b+d<=N) Link(mark[b],mark[b+d]); else Link(mark[b],Null); } } return 0; }