[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 }

 

posted @ 2019-08-26 20:13  祈梦生  阅读(78)  评论(0编辑  收藏