BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊 LCT

来源:互联网 发布:数据分析入门书籍 编辑:程序博客网 时间:2024/04/27 01:23

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

Sample Output

2
3

HINT

Source


一道LCT的入门题目……
因为这题只需要维护size就好了。
我们可以看到,假如说对于x,它当前的弹力系数是a[x],那么它会弹到x+a[x];
我们可以把x+a[x]看作它的父亲。如此我们就可以建立起一棵树了。
查询事实上就是查询点p到根节点的距离。
但是修改呢?
我们看到,这题的修改操作是修改一个点的父亲,导致了树的结构发生了改变。
所以我们这个时候就要用LCT了:用splay来维护信息。。

不得不说splay真的坑爹,,,TLE了好久,然后是splay错了。。
因为LCT中splay里可能出现splay tree的结构“玄学”的情况……
决定换一个splay模板了!
最后怎么改对的呢。。。还是看了hzw大神的题解……QAQ。。。

#include<bits/stdc++.h>using namespace std;int read(){int x=0,f=1;char ch=getchar();while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}const intN=200010;int n,m,Next[N];struct Tree{int pre,sz,son[2];bool rev;}tree[N];bool isroot(int x){return tree[tree[x].pre].son[0]!=x &&   tree[tree[x].pre].son[1]!=x;}void up(int x){if (x){tree[x].sz=1;if (tree[x].son[0]) tree[x].sz+=tree[tree[x].son[0]].sz;if (tree[x].son[1]) tree[x].sz+=tree[tree[x].son[1]].sz;}}void down(int x){if (x && tree[x].rev){swap(tree[x].son[0],tree[x].son[1]);tree[tree[x].son[0]].rev^=1;tree[tree[x].son[1]].rev^=1;tree[x].rev^=1;}}void Rotate(int x){    int y=tree[x].pre,z=tree[y].pre,l,r;    if (tree[y].son[0]==x) l=0; else l=1;r=l^1;    if (!isroot(y))        if (tree[z].son[0]==y)tree[z].son[0]=x; elsetree[z].son[1]=x;    tree[x].pre=z;tree[y].pre=x;tree[tree[x].son[r]].pre=y;    tree[y].son[l]=tree[x].son[r];tree[x].son[r]=y;up(y); up(x);}int stk[N];void splay(int x){    int y,z,top=0;stk[++top]=x;    for (int i=x;!isroot(i);i=tree[i].pre)        stk[++top]=tree[i].pre;    for (int i=top;i;i--)down(stk[i]);    while(!isroot(x)){        y=tree[x].pre,z=tree[y].pre;        if(!isroot(y)){            if(tree[y].son[0]==x^tree[z].son[0]==y) Rotate(x);            else Rotate(y);        }        Rotate(x);    }}void access(int x){int y=0;while (x){splay(x);tree[x].son[1]=y;y=x; x=tree[x].pre;}}void reverse(int x){access(x); splay(x);tree[x].rev^=1;}void cut(int x,int y){reverse(x);access(y);splay(y);tree[y].son[0]=tree[x].pre=0;}void link(int x,int y){reverse(x);tree[x].pre=y;splay(x);}int main(){n=read(); int x;for (int i=1;i<=n;i++){x=read();Next[i]=tree[i].pre=min(i+x,n+1);tree[i].sz=1;}tree[n+1].sz=1;m=read();int opt,y,tmp;while (m--){opt=read();if (opt==1){reverse(n+1);x=read()+1;access(x); splay(x);printf("%d\n",tree[tree[x].son[0]].sz);}else{x=read()+1,y=read();tmp=min(x+y,n+1);cut(x,Next[x]);link(x,tmp); Next[x]=tmp;}}return 0;}