[BZOJ2002] [Hnoi2010] Bounce 弹飞绵羊 (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

HINT 

Source

Solution

  每个点和可以到达的点连一条边,支持动态链上查询,LCT大法好

  用和splay一样的方法维护子树大小siz即可。

  感谢Ngshily大爷的版子!!!

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 struct LCT
  4 {
  5     int c[2], fa, rev, siz;
  6     int& operator [] (int i)
  7     {
  8         return c[i];
  9     }
 10 }a[200005];
 11 int sta[200005], top, nxt[200005];
 12  
 13 void scanf(int *x)
 14 {
 15     char ch = getchar();
 16     *x = 0;
 17     while(ch < '0' || ch > '9')
 18         ch = getchar();
 19     while(ch >= '0' && ch <= '9')
 20         *x = *x * 10 + ch - 48, ch = getchar();
 21 }
 22  
 23 void push_up(int k)
 24 {
 25     a[k].siz = a[a[k][0]].siz + a[a[k][1]].siz + 1;
 26 }
 27  
 28 void push_down(int k)
 29 {
 30     if(a[k].rev)
 31     {
 32         a[a[k][0]].rev ^= 1, a[a[k][1]].rev ^= 1;
 33         swap(a[k][0], a[k][1]), a[k].rev = 0;
 34     }
 35 }
 36  
 37 bool isroot(int x)
 38 {
 39     return a[a[x].fa][0] != x && a[a[x].fa][1] != x;
 40 }
 41  
 42 void rotate(int x)
 43 {
 44     int y = a[x].fa, z = a[y].fa;
 45     int dy = a[y][1] == x, dz = a[z][1] == y;
 46     if(!isroot(y)) a[z][dz] = x;
 47     a[y][dy] = a[x][dy ^ 1], a[a[x][dy ^ 1]].fa = y;
 48     a[x][dy ^ 1] = y, a[y].fa = x, a[x].fa = z;
 49     push_up(y);
 50 }
 51  
 52 void splay(int x)
 53 {
 54     sta[top = 1] = x;
 55     for(int i = x; !isroot(i); i = a[i].fa)
 56         sta[++top] = a[i].fa;
 57     while(top)
 58         push_down(sta[top--]);
 59     while(!isroot(x))
 60     {
 61         int y = a[x].fa, z = a[y].fa;
 62         if(!isroot(y))
 63             if(a[y][1] == x ^ a[z][1] == y) rotate(x);
 64             else rotate(y);
 65         rotate(x);
 66     }
 67     push_up(x);
 68 }
 69  
 70 void access(int x)
 71 {
 72     for(int i = 0; x; x = a[x].fa)
 73         splay(x), a[x][1] = i, i = x;
 74 }
 75  
 76 void make_root(int x)
 77 {
 78     access(x), splay(x), a[x].rev ^= 1;
 79 }
 80  
 81 int find_root(int x)
 82 {
 83     access(x), splay(x);
 84     while(a[x][0])
 85         x = a[x][0];
 86     return x;
 87 }
 88  
 89 void link(int x, int y)
 90 {
 91     make_root(x), a[x].fa = y;
 92 }
 93  
 94 void cut(int x, int y)
 95 {
 96     make_root(x), access(y), splay(y), a[y][0] = a[x].fa = 0;
 97 }
 98  
 99 int main()
100 {
101     int n, m, x, y, op;
102     scanf(&n);
103     for(int i = 1; i <= n; i++)
104     {
105         scanf(&x), a[i].siz = 1;
106         a[i].fa = nxt[i] = min(i + x, n + 1);
107     }
108     scanf(&m), a[n + 1].siz = 1;
109     while(m--)
110     {
111         scanf(&op), scanf(&x), x++;
112         if(op == 1)
113         {
114             make_root(n + 1), access(x), splay(x);
115             printf("%d\n", a[x].siz - 1);
116         }
117         else
118         {
119             scanf(&y), cut(nxt[x], x);
120             nxt[x] = min(x + y, n + 1);
121             link(nxt[x], x);
122         }
123     }
124     return 0;
125 }
View Code
posted @ 2016-04-08 22:28  CtrlCV  阅读(227)  评论(0编辑  收藏  举报