题目描述
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
输入输出格式
输入格式:
第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1。
接下来一行有n个正整数,依次为那n个装置的初始弹力系数。
第三行有一个正整数m,
接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。
输出格式:
对于每个i=1的情况,你都要输出一个需要的步数,占一行。
输入输出样例
说明
对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000
题解
用这题来练练LCT吧……话说wjz大佬讲的LCT几乎没怎么听懂啊QAQ我好菜
话说关于LCT,这两位大佬的blog很不错
http://www.cnblogs.com/zwfymqz/p/8972914.html#_label5
http://www.cnblogs.com/flashhu/p/8324551.html
首先我们考虑,对于每一个节点,向他被弹到的节点连边。即对于所有节点建一棵树,i节点的父亲为从i装置会被弹飞到哪一个装置。
我们定义一个虚拟节点n+1,让所有被弹飞到大于n的点连到n+1。可以看出,到了n+1就意味着已经被弹飞
对于修改操作,先将点与原先的连边cut,再link到新的点上
对于查询操作,我们依次执行makeroot(x),access(y),splay(y),这个时候可以发现x的深度即为答案。而因为此时splay已经是一条链,所以答案就是sz[y]-1(sz表示以y为根的子树的大小)
1 //minamoto 2 #include<cstdio> 3 #include<algorithm> 4 #include<cctype> 5 #define N 200005 6 using namespace std; 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<15,stdin),p1==p2)?EOF:*p1++) 8 char buf[1<<15],*p1=buf,*p2=buf; 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 namespace lct{ 20 int top,s[N],ch[N][2],fa[N],sz[N],v[N];bool rev[N]; 21 inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} 22 inline void pushup(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;} 23 inline void pushdown(int x){if(rev[x])swap(ch[x][0],ch[x][1]),rev[ch[x][0]]^=1,rev[ch[x][1]]^=1,rev[x]^=1;} 24 inline void rotate(int x){ 25 int y=fa[x],z=fa[y],d=(ch[y][1]==x);if(!isroot(y)) ch[z][ch[z][1]==y]=x; 26 fa[x]=z,fa[y]=x;fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y;pushup(y),pushup(x); 27 } 28 inline void splay(int x){ 29 s[top=1]=x;for(int i=x;!isroot(i);i=fa[i]) s[++top]=fa[i];for(int i=top;i>=1;--i) pushdown(s[i]); 30 for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){ 31 if(!isroot(y)) ((ch[z][1]==y)^(ch[y][1]==x))?rotate(x):rotate(y);rotate(x); 32 } 33 } 34 inline void access(int x){int t=0;while(x){splay(x),ch[x][1]=t,pushup(x),t=x,x=fa[x];}} 35 inline void makeroot(int x){access(x),splay(x),rev[x]^=1;} 36 inline void split(int x,int y){makeroot(x),access(y),splay(y);} 37 inline void link(int x,int y){makeroot(x);fa[x]=y;} 38 inline void cut(int x,int y){makeroot(x);access(y),splay(y);fa[x]=ch[y][0]=0;pushup(y);} 39 inline int query(int x,int y){makeroot(x),access(y),splay(y);return sz[y]-1;} 40 } 41 using namespace lct; 42 int main(){ 43 //freopen("testdata.in","r",stdin); 44 int n,m; 45 n=read(); 46 for(int i=1;i<=n+1;++i) sz[i]=1; 47 for(int i=1;i<=n;++i){ 48 v[i]=read(); 49 if(i+v[i]<=n) link(i,i+v[i]); 50 else link(i,n+1); 51 } 52 m=read(); 53 while(m--){ 54 int opt=read(),i=read();++i; 55 if(opt==1){ 56 printf("%d ",query(i,n+1)); 57 } 58 else{ 59 int k=read(); 60 cut(i,i+v[i]<=n?i+v[i]:n+1); 61 link(i,i+k<=n?i+k:n+1); 62 v[i]=k; 63 } 64 } 65 return 0; 66 }