2002. [HNOI2010]弹飞绵羊【LCT】

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

把每个点像弹到的点连边,显然可得出一棵树。
而x能弹几下显然就是x到树中在序列中最靠右的点的路径的size
可是如果维护森林的话,很难知道这个splay中最大的是哪一个
为了方便把弹飞的都连接到n+1点上,那么x弹的次数就是x到n+1的路径的size-1
查询和修改操作详见代码

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define N (200000+100)
 5 using namespace std;
 6 int Father[N],Son[N][2],Size[N],Rev[N];
 7 int n,m,a[N];
 8 
 9 int Get(int x) {return Son[Father[x]][1]==x;}
10 int Is_root(int x) {return Son[Father[x]][1]!=x && Son[Father[x]][0]!=x;}
11 void Update(int x) {Size[x]=Size[Son[x][0]]+Size[Son[x][1]]+1;}
12 
13 void Rotate(int x) 
14 {
15     int wh=Get(x);
16     int fa=Father[x],fafa=Father[fa];
17     if (!Is_root(fa)) Son[fafa][Son[fafa][1]==fa]=x;
18     Father[fa]=x; Son[fa][wh]=Son[x][wh^1];
19     Father[x]=fafa; Son[x][wh^1]=fa;
20     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
21     Update(fa);    Update(x);
22 }
23 
24 void Pushdown(int x)
25 {
26     if (Rev[x] && x)
27     {
28         if (Son[x][0]) Rev[Son[x][0]]^=1;
29         if (Son[x][1]) Rev[Son[x][1]]^=1;
30         swap(Son[x][0],Son[x][1]);
31         Rev[x]=0;
32     }
33 }
34 
35 void Push(int x)
36 {
37     if (!Is_root(x)) Push(Father[x]);
38     Pushdown(x);
39 }
40 
41 void Splay(int x)
42 {
43     Push(x);
44     for (int fa;!Is_root(x);Rotate(x))
45         if (!Is_root(fa=Father[x]))
46             Rotate(Get(fa)==Get(x)?fa:x);
47 }
48 
49 void Access(int x) {for (int y=0;x;y=x,x=Father[x]) Splay(x),Son[x][1]=y,Update(x);}
50 void Make_root(int x) {Access(x); Splay(x); Rev[x]^=1;}
51 int Find_root(int x) {Access(x); Splay(x); while (Son[x][0]) x=Son[x][0]; return x;}
52 void Link(int x,int y) {Make_root(x); Father[x]=y;}
53 void Cut(int x,int y) {Make_root(x); Access(y); Splay(y); Father[x]=Son[y][0]=0;}
54 void Query(int x) {Make_root(n+1); Access(x); Splay(x); printf("%d
",Size[x]-1);}
55 void Change(int x,int y) {Cut(x,x+a[x]<=n?x+a[x]:n+1); Link(x,x+y<=n?x+y:n+1); a[x]=y;}
56 
57 int main()
58 {
59     int opt,x,y;
60     scanf("%d",&n);
61     for (int i=1;i<=n;++i)
62     {
63         scanf("%d",&a[i]);
64         if (i+a[i]<=n) Link(i,i+a[i]);
65         else Link(i,n+1);
66     }
67     scanf("%d",&m);
68     for (int i=1;i<=m;++i)
69     {
70         scanf("%d",&opt);
71         if (opt==1)    scanf("%d",&x),Query(x+1);
72         if (opt==2)    scanf("%d%d",&x,&y),Change(x+1,y);
73     }
74 }
原文地址:https://www.cnblogs.com/refun/p/8680738.html