First glance of Top Tree.

Table of Contents

主要思想来自Claris的博客.

开始搞很久之前的一个flag。

这种数据结构也算Top Tree的范畴,但是好多人似乎更愿意叫她AAA树。

LCT是不能做子树的,当前的Splay只能维护重链上的信息。

那么我们不妨把虚儿子也装到一颗Splay里。

由于虚儿子不存在父子关系关系,我们需要让虚儿子都是Splay的叶子,这时需要引入内部点来占位。

新增的两项操作是Add和Del,也就是添加虚边和删除虚边,必要时添加内部点和删除内部点。

这样在Access操作引发的变化就是,把原来的x挂到父亲右儿子的操作变为:断开自己虚边,添加父亲原右儿子的虚边,连自己和父亲右儿子的实边。

Link操作就加一条虚边。

其他操作大致相同。

下面说维护数据。分别维护三组数据和两个标记:实数据,虚数据,全部数据,实标记,虚标记。

对于实链Splay,用实数据维护。虚边Splay,应该是实边Splay上左右儿子的虚数据+虚边Splay左右儿子的全部数据。

全部数据就是实数据加虚数据。

下放标记时,实标记只影响实链Splay的儿子,翻转标记也是,虚标记除了影响所有儿子的虚数据外,还要注意可能影响虚儿子中的实链。

代码奇长无比,可以结合理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 200005;
const int inf = ~0U>>1;

struct tag
{
int x, y;
tag() {x = 1; y = 0;}
tag(int x_, int y_):x(x_),y(y_){}
bool aval() {
return x != 1 || y;
}
tag operator + (const tag &rhs) const {
return tag(x*rhs.x, y*rhs.x+rhs.y);
}
};
int atag(int lhs, tag rhs) {
return lhs * rhs.x + rhs.y;
}
struct data
{
int sum, minv, maxv, siz;
data() {
sum = siz = 0; minv = inf; maxv = -inf;
}
data(int x) {
sum = minv = maxv = x; siz = 1;
}
data(int a, int b, int c, int d) {
sum = a; minv = b; maxv = c; siz = d;
}
data operator + (const data &rhs) {
return data(sum + rhs.sum, min(minv, rhs.minv), max(maxv, rhs.maxv), siz + rhs.siz);
}
friend data operator + (const data &lhs, const tag &rhs) {
return lhs.siz ? data(lhs.sum * rhs.x + lhs.siz * rhs.y, atag(lhs.minv, rhs), atag(lhs.maxv, rhs), lhs.siz) : lhs;
}
};
int f[maxn], ch[maxn][4], a[maxn], cnt, rt;
int rub[maxn], rubcnt;
bool rev[maxn], in[maxn];
int val[maxn];

data chains[maxn], subs[maxn], alls[maxn];
tag chaint[maxn], subt[maxn];

inline int isroot(int x, int t) {
if (t) return !f[x] || !in[f[x]] || !in[x];
return !f[x] || (ch[f[x]][0] != x && ch[f[x]][1] != x) || in[f[x]] || in[x];
}
inline void rever(int x) {
if (!x) return;
swap(ch[x][0], ch[x][1]); rev[x] ^= 1;
}
inline void chain_tag(int x, tag p) {
if (!x) return;
chains[x] = chains[x] + p;
alls[x] = chains[x] + subs[x];
val[x] = atag(val[x], p);
chaint[x] = chaint[x] + p;
}
inline void tree_tag(int x, tag p, bool t) {
if (!x) return;
subs[x] = subs[x] + p;
subt[x] = subt[x] + p;
if (!in[x] && t) chain_tag(x, p);
else alls[x] = chains[x] + subs[x];
}
inline void pushdown(int x) {
if (!x) return;
if (rev[x]) rever(ch[x][0]), rever(ch[x][1]), rev[x] = 0;
if (!in[x] && chaint[x].aval())
chain_tag(ch[x][0], chaint[x]),
chain_tag(ch[x][1], chaint[x]),
chaint[x] = tag();
if (subt[x].aval()) {
tree_tag(ch[x][0], subt[x], 0);
tree_tag(ch[x][1], subt[x], 0);
tree_tag(ch[x][2], subt[x], 1);
tree_tag(ch[x][3], subt[x], 1);
subt[x] = tag();
}
}
inline void pushup(int x) {
subs[x] = data();
for (int i = 0; i < 2; ++i) if (ch[x][i]) subs[x] = subs[x] + subs[ch[x][i]];
for (int i = 2; i < 4; ++i) if (ch[x][i]) subs[x] = subs[x] + alls[ch[x][i]];
if (in[x]) {
chains[x] = data();
alls[x] = subs[x];
} else {
chains[x] = data(val[x]);
for (int i = 0; i < 2; ++i) if(ch[x][i]) chains[x] = chains[x] + chains[ch[x][i]];
alls[x] = chains[x] + subs[x];
}
}
inline int get_child(int x, int t) {
pushdown(ch[x][t]);
return ch[x][t];
}
inline void rotate(int x, int t) {
int y = f[x], w = (ch[y][t + 1] == x) + t;
ch[y][w] = ch[x][w ^ 1];
if (ch[x][w ^ 1]) f[ch[x][w ^ 1]] = y;
if (f[y])
for (int z = f[y], i = 0; i < 4; ++i)
if (ch[z][i] == y)
ch[z][i] = x;
f[x] = f[y];
f[y] = x;
ch[x][w ^ 1] = y;
pushup(y);
}
void pushpath (int x, int t) {
if (!isroot(x, t)) pushpath(x, t);
pushdown(x);
}
inline void splay(int x, int t = 0) {
//pushpath(x, t);
//printf("spl %d %d\n", x, t);
int y;
int stk = 1, i = x; a[1] = i;
while (!isroot(i, t)) a[++stk] = i = f[i];
while (stk) pushdown(a[stk--]);
while (!isroot(x, t)) {
y = f[x];
if (!isroot(y, t)) {
rotate(((ch[f[y]][t] == y) ^ (ch[y][t] == x)) ? x : y, t);
}
rotate(x, t);
}
pushup(x);
}
inline int newnode() {
int x = (rubcnt ? rub[rubcnt--] : ++cnt);
ch[x][2] = ch[x][3] = 0; in[x] = 1;
return x;
}
inline void setson(int x, int t, int y) {
ch[x][t] = y; f[y] = x;
}
inline int getid(int x) {
for (int i = 0; i < 4; ++i) if (ch[f[x]][i] == x) return i;
return 4;
}
inline void ADD(int x, int y) {
if (!y) return;
pushdown(x);
for (int i = 2; i < 4; ++i) if (!ch[x][i]) {
setson(x, i, y);
return;
}
while (ch[x][2] && in[ch[x][2]]) x = get_child(x, 2);
int np = newnode();
setson(np, 2, ch[x][2]);
setson(np, 3, y);
setson(x, 2, np);
splay(np, 2);
}
inline void DEL(int x) {
if (!x) return;
splay(x);
if (!f[x]) return;
int y = f[x];
if (in[y]) {
//pushpath(y, 2);
int stk = 1, i = y; a[1] = i;
while (!isroot(i, 2)) a[++stk] = i = f[i];
while (stk) pushdown(a[stk--]);
int anc = f[y];
if (anc) {
setson(anc, getid(y), get_child(y, getid(x) ^ 1));
splay(anc, 2);
}
rub[++rubcnt] = y;
} else {
ch[y][getid(x)] = 0;
splay(y);
}
f[x] = 0;
}
inline int fa(int x) {
splay(x);
if (!f[x]) return 0;
if (!in[f[x]]) return f[x];
int y = f[x];
splay(y, 2);
return f[y];
}
inline int access(int x) {
int y = 0;
for (; x; y = x, x = fa(x)) {
splay(x);
DEL(y);
ADD(x, ch[x][1]);
setson(x, 1, y);
pushup(x);
}
return y;
}
inline int lca(int x, int y) {
access(x);
return access(y);
}
inline int findroot(int x) {
access(x);
splay(x);
while (ch[x][0]) x = ch[x][0];
return x;
}
inline void makeroot(int x) {
access(x); splay(x); rever(x);
}
inline void link(int x, int y) {
makeroot(x);
ADD(y, x);
access(x);
}
inline void cut(int x) {
access(x);
splay(x);
f[ch[x][0]] = 0;
ch[x][0] = 0;
pushup(x);
}
inline void split(int x, int y) {
makeroot(x);
access(y);
splay(y);
}
inline void ChainUpdate(int x, int y, tag p) {
split(x, y);
chain_tag(y, p);
}
inline data ChainQuery(int x, int y) {
split(x, y);
return chains[y];
}
inline void SubtreeUpdate(int x, tag p) {
access(x);
splay(x);
val[x] = atag(val[x], p);
for (int i = 2; i < 4; ++i) if (ch[x][i]) tree_tag(ch[x][i], p, 1);
pushup(x);
splay(x);
}
inline data SubtreeQuery(int x) {
access(x);
splay(x);
data ret = data(val[x]);
for (int i = 2; i < 4; ++i) if (ch[x][i]) ret = ret + alls[ch[x][i]];
return ret;
}
inline int rd() {
register int x = 0, f = 0, c = getchar();
while (!isdigit(c)) {
if (c == '-') f = 1;
c = getchar();
}
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return f ? -x : x;
}
int n, m, x, y, z, i, Edge[maxn][2];

int main() {
//freopen("3153.in", "r", stdin);
//freopen("3153.out","w",stdout);
n = rd(); m = rd();
cnt = n;
for (int i = 1; i < n; ++i)
Edge[i][0] = rd(), Edge[i][1] = rd();
for (int i = 1; i <= n; ++i)
val[i] = rd(), pushup(i);
for (int i = 1; i < n; ++i)
link(Edge[i][0], Edge[i][1]);
rt = rd();
makeroot(rt);
int Type;
//puts("begin");
while (m--) {
//puts("opt");
Type = rd();
switch (Type) {
case 0: {
x = rd(); y = rd();
SubtreeUpdate(x, tag(0, y)); break;
} case 1: {
rt = rd();
makeroot(rt); break;
} case 2: {
x = rd(); y = rd(); z = rd();
ChainUpdate(x, y, tag(0, z)); makeroot(rt); break;
} case 3: {
x = rd(); data d = SubtreeQuery(x);
printf("%d\n", d.minv); break;
} case 4: {
x = rd(); data d = SubtreeQuery(x);
printf("%d\n", d.maxv); break;
} case 5: {
x = rd(); y = rd();
SubtreeUpdate(x, tag(1, y)); break;
} case 6: {
x = rd(); y = rd(); z = rd();
ChainUpdate(x, y, tag(1, z)); makeroot(rt); break;
} case 7: {
x = rd(); y = rd(); data d = ChainQuery(x, y);
printf("%d\n", d.minv); makeroot(rt); break;
} case 8: {
x = rd(); y = rd(); data d = ChainQuery(x, y);
printf("%d\n", d.maxv); makeroot(rt); break;
} case 9: {
x = rd(); y = rd();
if (lca(x, y) == x) continue;
cut(x); link(y, x); makeroot(rt); break;
} case 10: {
x = rd(); y = rd(); data d = ChainQuery(x, y);
printf("%d\n", d.sum); makeroot(rt); break;
} case 11: {
x = rd(); data d = SubtreeQuery(x);
printf("%d\n", d.sum); break;
}
}
}
return 0;
}