主要思想来自Claris的博客.
开始搞很久之前的一个flag。
这种数据结构也算Top Tree的范畴,但是好多人似乎更愿意叫她AAA树。
LCT是不能做子树的,当前的Splay只能维护重链上的信息。
那么我们不妨把虚儿子也装到一颗Splay里。
由于虚儿子不存在父子关系关系,我们需要让虚儿子都是Splay的叶子,这时需要引入内部点来占位。
新增的两项操作是Add和Del,也就是添加虚边和删除虚边,必要时添加内部点和删除内部点。
这样在Access操作引发的变化就是,把原来的x挂到父亲右儿子的操作变为:断开自己虚边,添加父亲原右儿子的虚边,连自己和父亲右儿子的实边。
Link操作就加一条虚边。
其他操作大致相同。
下面说维护数据。分别维护三组数据和两个标记:实数据,虚数据,全部数据,实标记,虚标记。
对于实链Splay,用实数据维护。虚边Splay,应该是实边Splay上左右儿子的虚数据+虚边Splay左右儿子的全部数据。
全部数据就是实数据加虚数据。
下放标记时,实标记只影响实链Splay的儿子,翻转标记也是,虚标记除了影响所有儿子的虚数据外,还要注意可能影响虚儿子中的实链。
代码奇长无比,可以结合理解。
#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;
}