[bzoj2002][Hnoi2010]Bounce 弹飞绵羊(LCT)
第一次做LCT的题目还有点小激动QAQ
如果将题目所给的关系简化,将弹飞看做是树的根节点,则整个序列就可以看做是一棵树。然后修改操作就是修改一个节点的父节点,查询操作就是查询一个节点的深度。
如果是修改操作,就是先断边再连边,如果是查询操作,就将x与根节点连在一颗splay中,然后查询这颗splay的节点数,这个就是我们维护的siz大小+1。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 3e5 + 10; 5 int fa[maxn], ch[maxn][2], siz[maxn], val[maxn], lazy[maxn], st[maxn];//父亲节点,左右儿子节点,当前子数节点个数,当前值,lazy标记,辅助数组。 6 inline int read() { 7 int x = 0, f = 1; char ch = getchar(); 8 while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } 9 while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); } 10 return x * f; 11 } 12 inline bool isroot(int x) {//判断x是否为所在splay的根 13 return ch[fa[x]][0] != x && ch[fa[x]][1] != x; 14 } 15 inline void pushup(int x) { 16 siz[x] = siz[ch[x][1]] + siz[ch[x][0]] + 1; 17 } 18 inline void pushdown(int x) { 19 if (lazy[x]) { 20 swap(ch[x][0], ch[x][1]); 21 if (ch[x][0])lazy[ch[x][0]] ^= 1; 22 if (ch[x][1])lazy[ch[x][1]] ^= 1; 23 lazy[x] = 0; 24 } 25 } 26 inline void rotate(int x) { 27 int y = fa[x], z = fa[y]; 28 int k = ch[y][1] == x; 29 if (!isroot(y)) 30 ch[z][ch[z][1] == y] = x; 31 fa[x] = z; ch[y][k] = ch[x][k ^ 1]; fa[ch[x][k ^ 1]] = y; 32 ch[x][k ^ 1] = y; fa[y] = x; 33 pushup(y); 34 pushup(x); 35 } 36 inline void splay(int x) { 37 int f = x, len = 0; 38 st[++len] = f; 39 while (!isroot(f))st[++len] = f = fa[f]; 40 while (len)pushdown(st[len--]); 41 while (!isroot(x)) { 42 int y = fa[x]; 43 int z = fa[y]; 44 if (!isroot(y)) 45 rotate((ch[y][0] == x) ^ (ch[z][0] == y) ? x : y); 46 rotate(x); 47 } 48 pushup(x); 49 } 50 inline void access(int x) {//打通根节点到x的实链 51 for (int y = 0; x; x = fa[y = x]) 52 splay(x), ch[x][1] = y, pushup(x); 53 } 54 inline void makeroot(int x) {//将x变为原树的根 55 access(x); splay(x); lazy[x] ^= 1; 56 } 57 int Findroot(int x) {//找根节点 58 access(x), splay(x); 59 while (ch[x][0]) 60 pushdown(x), x = ch[x][0]; 61 splay(x); 62 return x; 63 } 64 inline void split(int x, int y) { makeroot(x); access(y); splay(y); } 65 inline void Link(int x, int y) { makeroot(x); fa[x] = y; } 66 inline void cut(int x, int y) { makeroot(x); access(y); splay(y); fa[x] = ch[y][0] = 0; pushup(y); }//合法断边 67 int main() { 68 int n, m; 69 n = read(); 70 for (int i = 1; i <= n; i++) { 71 val[i] = read(); 72 if (i + val[i] <= n) 73 Link(i, i + val[i]); 74 else 75 Link(i, n + 1); 76 } 77 m = read(); 78 while (m--) { 79 int opt, x, y; 80 opt = read(), x = read() + 1; 81 if (opt == 2) { 82 y = read(); 83 cut(x, x + val[x] <= n ? x + val[x] : n + 1); 84 Link(x, x + y <= n ? x + y : n + 1); 85 val[x] = y; 86 } 87 else { 88 split(x, n + 1); 89 printf("%d\n", siz[n + 1] - 1); 90 } 91 }92 }