【传送门:BZOJ2002】
简要题意:
给出n个点,一个人站在i点一开始可以飞到i+a[i]的地方,一旦飞出了n-1的位置就算作弹飞了
有m种操作,其中一种可以改变a[i],另一种是求出从i点开始飞多少次就会被弹飞
题解:
LCT例题
因为原题中的位置是0到n-1,所以我们把位置弄成1到n,好处理一点
题目就变成一旦飞出了n的位置就算作弹飞了
然后对于会被弹飞的时候,就相当于飞到n+1的位置
然后就将i与i+a[i]连通(如果i+a[i]>n,则连向n+1)
对于修改a[i],实际上就是删边然后重建
求值的时候就用伸展树的基本操作来做
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int f,son[2],c,n; bool fz; }tr[210000]; void update(int x) { int lc=tr[x].son[0],rc=tr[x].son[1]; tr[x].c=tr[lc].c+tr[rc].c+tr[x].n; } void reverse(int x) { tr[x].fz=false; swap(tr[x].son[0],tr[x].son[1]); int lc=tr[x].son[0],rc=tr[x].son[1]; tr[lc].fz=1-tr[lc].fz; tr[rc].fz=1-tr[rc].fz; } void rotate(int x,int w) { int f=tr[x].f,ff=tr[f].f; int r,R; r=tr[x].son[w];R=f; tr[R].son[1-w]=r; if(r!=0) tr[r].f=R; r=x;R=ff; if(tr[R].son[0]==f) tr[R].son[0]=r; else if(tr[R].son[1]==f) tr[R].son[1]=r; tr[r].f=R; r=f;R=x; tr[R].son[w]=r; tr[r].f=R; update(f);update(x); } int tmp[210000]; void splay(int x,int rt) { int i=x,s=0; while(tr[i].f!=0&&(tr[tr[i].f].son[0]==i||tr[tr[i].f].son[1]==i)) { tmp[++s]=i; i=tr[i].f; } tmp[++s]=i; while(s!=0) { i=tmp[s--]; if(tr[i].fz==true) reverse(i); } while(tr[x].f!=rt&&(tr[tr[x].f].son[0]==x||tr[tr[x].f].son[1]==x)) { int f=tr[x].f,ff=tr[f].f; if(ff==rt||(tr[ff].son[0]!=f&&tr[ff].son[1]!=f)) { if(tr[f].son[0]==x) rotate(x,1); else if(tr[f].son[1]==x) rotate(x,0); } else { if(tr[f].son[0]==x&&tr[ff].son[0]==f){rotate(f,1);rotate(x,1);continue;} if(tr[f].son[0]==x&&tr[ff].son[1]==f){rotate(x,1);rotate(x,0);continue;} if(tr[f].son[1]==x&&tr[ff].son[0]==f){rotate(x,0);rotate(x,1);continue;} if(tr[f].son[1]==x&&tr[ff].son[1]==f){rotate(f,0);rotate(x,0);continue;} } } } void access(int x) { int y=0; while(x!=0) { splay(x,0); tr[x].son[1]=y; if(y!=0) tr[y].f=x; y=x;x=tr[x].f; } } void makeroot(int x) { access(x);splay(x,0); tr[x].fz=1-tr[x].fz; } void link(int x,int y) { makeroot(x); tr[x].f=y; access(x); } void cut(int x,int y) { makeroot(x); access(y); splay(y,0); tr[tr[y].son[0]].f=0;tr[y].son[0]=0; update(y); } int a[210000],n; int solve(int x) { makeroot(n+1); access(x);splay(x,0); return tr[tr[x].son[0]].c; } void bt() { for(int i=1;i<=n+1;i++) { tr[i].f=0; tr[i].c=tr[i].n=1; tr[i].son[0]=tr[i].son[1]=0; tr[i].fz=false; } } int main() { scanf("%d",&n); bt(); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); a[i]=i+a[i]; if(a[i]>n) a[i]=n+1; link(i,a[i]); } int m; scanf("%d",&m); for(int i=1;i<=m;i++) { int t,j,k; scanf("%d",&t); if(t==1) { scanf("%d",&j);j++; printf("%d ",solve(j)); } else { scanf("%d%d",&j,&k);j++; cut(j,a[j]); a[j]=j+k; if(a[j]>n) a[j]=n+1; link(j,a[j]); } } return 0; }