Solution
首先这道题可以用
Treap
加树链剖分。
LCT
的话,要维护两片
Splay
森林。
一片为形态树森林,就相当于最原来的
LCT
。
一片为值树森林,维护相应节点的权值。
通过对两片森林的同时操作,可以保证每时每刻两片森林可以通过旋转形态相同。
在形态树森林的根节点维护一个值树的指针,指向相应位置的值树森林的根节点。其余节点的指针指向空。
每次要找到形态树节点在值树对应的节点,就相当于在值树找到相应中序遍历的节点。
另外旋转的时候要把根节点的值树指针准确的转移。
LCT
还有一个操作就是
Access
。就是把一些实边变成虚边,一些虚边变成实边。
那么在值树上就是合并两棵
Splay
。
因为题目保证了深度是单调的,所以直接接上边就好了。
实现了好久哦。。。。
#include <bits/stdc++.h>
using namespace std;
const int N = 101010;
const int INF = 1 << 30;
typedef long long ll;
struct ValTree {
struct node {
node *ch[2];
node *fa;
int rev, mn, mx, key, add, size;
ll sum;
inline void PushDown(node *null) {
if (rev) {
if (ch[0] != null) ch[0]->reverse();
if (ch[1] != null) ch[1]->reverse();
rev = 0;
}
if (add) {
if (ch[0] != null) ch[0]->Add(add);
if (ch[1] != null) ch[1]->Add(add);
add = 0;
}
}
inline void Add(int ad) {
add += ad; key += ad;
mx += ad; mn += ad;
sum += (ll)ad * size;
}
inline void PushUp(void) {
mn = min(ch[0]->mn, ch[1]->mn);
mn = min(mn, key);
mx = max(ch[0]->mx, ch[1]->mx);
mx = max(mx, key);
sum = key + ch[0]->sum + ch[1]->sum;
size = ch[0]->size + ch[1]->size + 1;
}
inline void reverse(void) {
rev ^= 1; swap(ch[0], ch[1]);
}
};
node *null;
node T[N];
inline void Down(node *x) {
if (x->fa != null) Down(x->fa);
x->PushDown(null);
}
inline void Rotate(node *x) {
node *y = x->fa, *z = y->fa;
int l = (y->ch[0] != x), r = l ^ 1;
if (y->fa != null) {
if (z->ch[0] == y) z->ch[0] = x;
else z->ch[1] = x;
}
x->fa = z; y->fa = x; x->ch[r]->fa = y;
y->ch[l] = x->ch[r]; x->ch[r] = y;
y->PushUp(); x->PushUp();
}
inline void Splay(node *x) {
Down(x);
while (x->fa != null) {
node *y = x->fa, *z = y->fa;
if (y->fa != null) {
if (y->ch[0] == x ^ z->ch[0] == y) Rotate(x);
else Rotate(y);
}
Rotate(x);
}
}
inline node *Kth(node *x, int k) {
x->PushDown(null);
if (x->size < k) return null;
node *o = x;
while (k) {
o->PushDown(null);
if (o->ch[0]->size + 1 < k) {
k -= o->ch[0]->size + 1;
o = o->ch[1];
} else if (o->ch[0]->size >= k) {
o = o->ch[0];
} else break;
}
Splay(o); return o;
}
inline void NewNode(node *x) {
x->ch[0] = x->ch[1] = x->fa = null;
x->sum = x->key = x->size = 0;
x->mn = x->mx = 0;
x->rev = x->add = 0;
}
void Init(int n) {
NewNode(null = T);
null->mn = INF; null->mx = -1;
for (int i = 1; i <= n; i++) {
NewNode(T + i);
T[i].size = 1;
}
}
inline void Travel(node *x) {
if (x == null) return;
Travel(x->ch[0]);
printf("%d\n", x->key);
Travel(x->ch[1]);
}
};
ValTree VT;
typedef ValTree::node Vnode;
struct LCT {
struct node {
node *ch[2];
node *fa;
int rev, size;
Vnode *val;
inline void PushDown(void) {
if (rev) {
ch[0]->reverse();
ch[1]->reverse();
rev = 0;
}
}
inline void PushUp(void) {
size = ch[0]->size + ch[1]->size + 1;
}
inline void reverse(void) {
rev ^= 1; swap(ch[0], ch[1]);
}
};
node *null;
node T[N];
inline bool IsRoot(node *x) {
return x->fa == null || (x->fa->ch[0] != x && x->fa->ch[1] != x);
}
inline void Down(node *x) {
if (!IsRoot(x)) Down(x->fa);
x->PushDown();
}
inline void Rotate(node *x) {
node *y = x->fa, *z = y->fa;
int l = (y->ch[0] != x), r = l ^ 1;
if (!IsRoot(y)) {
if (z->ch[0] == y) z->ch[0] = x;
else z->ch[1] = x;
}
x->fa = z; y->fa = x; x->ch[r]->fa = y;
y->ch[l] = x->ch[r]; x->ch[r] = y;
y->PushUp(); x->PushUp();
swap(y->val, x->val);
}
inline void Splay(node *x) {
Down(x);
while (!IsRoot(x)) {
node *y = x->fa, *z = y->fa;
if (!IsRoot(y)) {
if (y->ch[0] == x ^ z->ch[0] == y) Rotate(x);
else Rotate(y);
}
Rotate(x);
}
}
inline void Access(node *x) {
for (node *t = null; x != null; x = x->fa) {
Splay(x);
if (x->ch[1] != null) {
int k = x->ch[0]->size + 2;
Vnode *y = VT.Kth(x->val, k);
Vnode *z = y->ch[0];
x->ch[1]->val = y;
y->ch[0]->fa = VT.null; y->ch[0] = VT.null; y->PushUp();
x->val = z; VT.Splay(x->val);
}
if (t != null) {
int k = x->val->size;
Vnode *y = VT.Kth(x->val, k);
y->ch[1] = t->val; t->val->fa = y; y->PushUp();
t->val = VT.null; VT.Splay(x->val);
}
x->ch[1] = t; x->PushUp(); t = x;
}
}
inline void MakeRoot(node *x) {
Access(x); Splay(x);
x->reverse(); x->val->reverse();
}
inline int Min(node *x, node *y) {
MakeRoot(x); Access(y); Splay(y);
return y->val->mn;
}
inline int Max(node *x, node *y) {
MakeRoot(x); Access(y); Splay(y);
return y->val->mx;
}
inline ll Sum(node *x, node *y) {
MakeRoot(x); Access(y); Splay(y);
return y->val->sum;
}
inline int Add(node *x, node *y, int k) {
MakeRoot(x); Access(y); Splay(y);
y->val->Add(k);
}
inline int Rev(node *x, node *y) {
MakeRoot(x); Access(y); Splay(y);
y->val->reverse();
}
void Init(int n) {
VT.Init(n); null = T;
null->fa = null->ch[0] = null->ch[1] = null;
null->size = 0;
for (int i = 1; i <= n; i++) {
T[i].val = VT.T + i;
T[i].fa = T[i].ch[0] = T[i].ch[1] = null;
T[i].size = 1; T[i].rev = 0;
}
}
inline void AddEdge(int x, int y) {
MakeRoot(T + x); T[x].fa = T + y;
}
};
LCT ST;
char opt[123];
int n, m, x, y, z;
int main(void) {
scanf("%d%d%d", &n, &m, &x);
ST.Init(n);
for (int i = 1; i < n; i++) {
scanf("%d%d\n", &x, &y);
ST.AddEdge(x, y);
}
for (int i = 1; i <= m; i++) {
scanf("%s %d%d", opt, &x, &y);
if (opt[2] == 'c') {
scanf("%d", &z);
ST.Add(ST.T + x, ST.T + y, z);
} else if (opt[0] == 'S') {
printf("%lld\n", ST.Sum(ST.T + x, ST.T + y));
} else if (opt[1] == 'a') {
printf("%d\n", ST.Max(ST.T + x, ST.T + y));
} else if (opt[0] == 'M') {
printf("%d\n", ST.Min(ST.T + x, ST.T + y));
} else {
ST.Rev(ST.T + x, ST.T + y);
}
}
return 0;
}