bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊
Submit: 6521 Solved: 3420
[Submit][Status][Discuss]
Description
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
Input
第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000
Output
对于每个i=1的情况,你都要输出一个需要的步数,占一行。
Sample Input
4
1 2 1 1
3
1 1
2 1 1
1 1
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
2
3
3
题解:
如果绵羊能从i跳到j,则连一条由i连向j的边,如果能被弹飞,连向n+1,连完之后会形成一个树结构。
由于可以更改弹力系数,所以树边之间存在断开和连接的操作,就是用动态树来完成。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 using namespace std; 9 const int N=200005; 10 inline int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 int n,m; 17 int next[N],c[N][2],fa[N],size[N],st[N]; 18 bool rev[N]; 19 bool isroot(int x){ 20 return x!=c[fa[x]][0]&&x!=c[fa[x]][1]; 21 } 22 void pushup(int x){ 23 size[x]=size[c[x][0]]+size[c[x][1]]+1; 24 } 25 void pushdown(int x){ 26 int l=c[x][0],r=c[x][1]; 27 if(rev[x]==true){ 28 rev[x]^=1; rev[l]^=1; rev[r]^=1; 29 swap(c[x][0],c[x][1]); 30 } 31 } 32 void rotate(int x){ 33 int y=fa[x],z=fa[y],l,r; 34 if(x==c[y][0]) l=0;else l=1; r=l^1; 35 if(!isroot(y)){ 36 if(y==c[z][0]) c[z][0]=x; 37 else c[z][1]=x; 38 } 39 fa[x]=z; fa[y]=x; fa[c[x][r]]=y; 40 c[y][l]=c[x][r]; c[x][r]=y; 41 pushup(y); pushdown(x); 42 } 43 void splay(int x){ 44 int top=0; st[++top]=x; 45 for(int i=x;isroot(i)==false;i=fa[i]){ 46 st[++top]=fa[i]; 47 } 48 for(int i=top;i;i--) pushdown(st[i]); 49 while(!isroot(x)){ 50 int y=fa[x],z=fa[y]; 51 if(!isroot(y)){ 52 if((x==c[y][0]&&y==c[z][0])||(x==c[y][1]&&y==c[z][1])){ 53 rotate(y),rotate(x); 54 } 55 else rotate(x),rotate(x); 56 } 57 else rotate(x); 58 } 59 } 60 void access(int x){ 61 int t=0; 62 while(x!=0){ 63 splay(x); 64 c[x][1]=t; 65 t=x; x=fa[x]; 66 } 67 } 68 void rever(int x){ 69 access(x); splay(x); rev[x]^=1; 70 } 71 void cut(int x,int y){ 72 rever(x); access(y); splay(y); c[y][0]=fa[x]=0; 73 } 74 void link(int x,int y){ 75 rever(x); fa[x]=y; splay(x); 76 } 77 int main(){ 78 n=read(); 79 for(int i=1;i<=n;i++){ 80 int x=read(); 81 fa[i]=x+i; size[i]=1; 82 if(fa[i]>n+1) fa[i]=n+1; 83 next[i]=fa[i]; 84 } 85 size[n+1]=1; 86 m=read(); 87 for(int i=1;i<=m;i++){ 88 int f=read(); 89 if(f==1){ 90 rever(n+1); 91 int x=read(); x++; 92 access(x); 93 splay(x); 94 printf("%d\n",size[c[x][0]]); 95 } 96 else{ 97 int x=read(),y=read(); x++; 98 int t=min(n+1,x+y); 99 cut(x,next[x]); 100 link(x,t); 101 next[x]=t; 102 } 103 } 104 return 0; 105 }