bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊 lct模板

来源:互联网 发布:软件研制方案模板 编辑:程序博客网 时间:2024/04/19 23:13

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

分析:很水的lct模板~~

先建成一棵树,每次查询的时候把x转到根节点,结果就是x右子数的节点数量。

修改的时候就直接把x与fa的边断开然后连到另一个点上就好了。


还有这题还可以用分块做,但笔者太懒,就不写啦~~


代码:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<stack>#define N 200005using namespace std;int n,next[N];struct tree{int fa,size,l,r,rev;}t[N];stack <int> q;void updata(int x){t[x].size=t[t[x].l].size+t[t[x].r].size+1;}void rttl(int x){int y=t[x].r;t[x].r=t[y].l;t[t[y].l].fa=x;if (x==t[t[x].fa].l) t[t[x].fa].l=y;else if (x==t[t[x].fa].r) t[t[x].fa].r=y;t[y].fa=t[x].fa;t[y].l=x;t[x].fa=y;updata(x);updata(y);}void rttr(int x){int y=t[x].l;t[x].l=t[y].r;t[t[y].r].fa=x;if (x==t[t[x].fa].l) t[t[x].fa].l=y;else if (x==t[t[x].fa].r) t[t[x].fa].r=y;t[y].fa=t[x].fa;t[y].r=x;t[x].fa=y;updata(x);updata(y);}bool isroot(int x){if (x!=t[t[x].fa].l&&x!=t[t[x].fa].r||!t[x].fa) return 1;return 0;}void pushdown(int x){if (t[x].rev){swap(t[x].l,t[x].r);if (t[x].l) t[t[x].l].rev^=1;if (t[x].r) t[t[x].r].rev^=1;t[x].rev^=1;}}void remove(int x){int y=x;while (1){q.push(y);if (isroot(y)) break;y=t[y].fa;}while (!q.empty()){int y=q.top();q.pop();pushdown(y);}}void splay(int x){remove(x);while (!isroot(x)){int p=t[x].fa,g=t[p].fa;if (isroot(p)){if (x==t[p].l) rttr(p);else rttl(p);break;}if (x==t[p].l){if (p==t[g].l){rttr(g);rttr(p);}else{rttr(p);rttl(g);}}else{if (p==t[g].r){rttl(g);rttl(p);}else{rttl(p);rttr(g);}}}}void access(int x){int y=0;while (x){splay(x);t[x].r=y;y=x;x=t[x].fa;}}void movetoroot(int x){access(x);splay(x);t[x].rev^=1;}void cut(int x,int y){movetoroot(x);access(y);splay(y);t[y].l=0;t[x].fa=0;}void link(int x,int y){movetoroot(x);access(y);t[y].r=x;t[x].fa=y;splay(x);}int findroot(int x){access(x);splay(x);while (t[x].l) x=t[x].l;return x;}int main(){scanf("%d",&n);for (int i=1;i<=n;i++){int k;scanf("%d",&k);t[i].fa=min(i+k,n+1);t[i].size=1;next[i]=t[i].fa;}t[n+1].size=1;int m;scanf("%d",&m);for (int i=1;i<=m;i++){int x;scanf("%d",&x);if (x==1){movetoroot(n+1);int y;scanf("%d",&y);y++;access(y);splay(y);printf("%d\n",t[t[y].l].size);}else{int y,z;scanf("%d%d",&y,&z);y++;int t=min(n+1,y+z);cut(y,next[y]);link(y,t);next[y]=t;}}return 0;}



0 0