题目链接 :http://acm.hdu.edu.cn/showproblem.php?pid=4010
LinkCutTree的模板题, 感觉LCT的思想和树链剖分差不多, 都是把树拆成若干条树链, LCT就是用Splay树维护每条链, 以节点的深度作为关键字, 代码主要是参考了这位神牛的blog:http://www.shuizilong.com/house/archives/hdu-4010-query-on-the-trees/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N = 300006;
const int M = N << 1;
inline int max(int a, int b, int c) {
return max(a, max(b, c));
}
struct LinkCutTree {
int head[N], to[M], next[M];
int tot;
int p[N], val[N], maxv[N], l[N], r[N], addv[N];
bool rev[N], rt[N];
int n;
#define lu l[u]
#define ru r[u]
#define pu p[u]
#define pv p[v]
void init(int n) {
this->n = n;
for (int i = 1; i <= n; i++) {
head[i] = -1;
rt[i] = 1;
l[i] = 0, r[i] = 0, addv[i] = 0, rev[i] = 0;
maxv[i] = 0;
}
tot = 0;
}
inline void add(int u, int v) {
to[tot] = v, next[tot] = head[u], head[u] = tot++;
to[tot] = u, next[tot] = head[v], head[v] = tot++;
}
inline void Inc(int u, int t) {
if (u == 0) return;
val[u] += t, maxv[u] += t, addv[u] += t;
}
inline void Set(int* a, int u, int v) {
a[u] = v, pv = u;
}
inline void push_up(int u) {
maxv[u] = max(val[u], maxv[lu], maxv[ru]);
}
inline void push_down(int u) {
if (u == 0) return;
if (rev[u]) {
swap(lu, ru);
rev[lu] ^= 1, rev[ru] ^= 1;
rev[u] = 0;
}
if (addv[u]) {
Inc(lu, addv[u]), Inc(ru, addv[u]);
addv[u] = 0;
}
}
inline void rotate(int u) {
int v = pu;
if (rt[v])
pu = pv;
else {
push_down(pv);
Set(pu == l[pv] ? l : r, pv, u);
}
push_down(v), push_down(u);
if (u == l[v]) {
Set(l, v, ru);
Set(r, u, v);
}
else {
Set(r, v, lu);
Set(l, u, v);
}
if (rt[v]) rt[u] = 1, rt[v] = 0;
push_up(v);
//cout << u << ' ' << pu << ' ' << v << "Yes" << endl;
}
void Splay(int u) {
while (!rt[u]) {
rotate(u);
}
}
int Access(int u) {
int v = 0;
do {
Splay(u), push_down(u);
rt[ru] = 1, rt[ru = v] = 0, push_up(u);
u = p[v = u];
} while (u);
return v;
}
void Evert(int u) {
rev[Access(u)] ^= 1;
}
int Root(int u) {
for (u = Access(u); push_down(u), lu; u = lu);
return u;
}
void Link(int u, int v) {
if (Root(u) == Root(v))
puts("-1");
else {
Evert(u), Splay(u), p[u] = v, Access(u);
}
}
void Cut(int v, int u) {
if (u == v || Root(u) != Root(v)) {
puts("-1");
}
else {
Evert(v), Splay(v), Access(u), Splay(u);
p[lu] = p[u], rt[lu] = 1, p[u] = lu = 0;
//p[lu] = 0, rt[lu] = 1, lu = 0;
}
}
void Modify(int u, int v, int d) {
if (Root(u) != Root(v))
puts("-1");
else {
Access(v), v = 0;
do {
Splay(u), push_down(u);
if (!p[u]) Inc(ru, d), val[u] += d, Inc(v, d);
rt[ru] = 1, rt[ru = v] = 0, push_up(u);
u = p[v = u];
} while (u);
}
}
void Query(int u, int v) {
if (Root(u) != Root(v))
puts("-1");
else {
Access(v), v = 0;
do {
Splay(u), push_down(u);
if (!p[u]) printf("%d\n", max(maxv[ru], maxv[v], val[u]));
rt[ru] = 1, rt[ru = v] = 0, push_up(u);
u = p[v = u];
} while (u);
}
}
void dfs(int u, int fa) {
p[u] = fa;
for (int i = head[u]; i != -1; i = next[i]) {
int v = to[i];
if (v == fa) continue;
dfs(v, u);
}
}
void gao() {
dfs(1, 0);
}
}T;
int main() {
int n, m, u, v, a, b, op, d;
while (~scanf("%d", &n)) {
T.init(n);
for (int i = 0; i < n - 1; i++) {
scanf("%d%d", &u, &v);
T.add(u, v);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &T.val[i]);
T.maxv[i] = T.val[i];
}
T.gao();
scanf("%d", &m);
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &op, &u, &v);
if (op == 1) {
T.Link(u, v);
}
else if (op == 2)
T.Cut(u, v);
else if (op == 4)
T.Query(u, v);
else {
scanf("%d", &a);
T.Modify(a, v, u);
}
}
puts("");
}
return 0;
}