#include <bits/stdc++.h>
#define mid ((l+r)/2)
#define ll long long
using namespace std;
const ll N = 1e6+5, INF = 0x3f3f3f3f;
using namespace std;
ll w[N], wnew[N];
//-----------------------线段树
ll sumn[N<<2], tag[N<<2], maxn[N<<2];
ll ls(ll p) {return p << 1;}
ll rs(ll p) {return p << 1 | 1;}
void push_up(ll p){
sumn[p] = sumn[ls(p)] + sumn[rs(p)];
maxn[p] = max(maxn[ls(p)], maxn[rs(p)]);
}
void build(ll p, ll l, ll r){
tag[p] = 0;
if(l == r){
sumn[p] = wnew[l];
maxn[p] = wnew[l];
return;
}
build(ls(p), l, mid);
build(rs(p), mid+1, r);
push_up(p);
}
void addtag(ll p, ll l, ll r, ll d){
tag[p] = d;
sumn[p] = (d * (r-l+1));
maxn[p] = (d * (r-l+1));
}
void push_down(ll p, ll l, ll r){
if(tag[p]){
addtag(ls(p), l, mid, tag[p]);
addtag(rs(p), mid+1, r, tag[p]);
tag[p] = 0;
}
}
void update(ll pl, ll pr, ll p, ll l, ll r, ll d){
if(pl <= l && r <= pr)
{
addtag(p, l, r, d);
return;
}
push_down(p, l, r);
if(pl <= mid) update(pl, pr, ls(p), l, mid, d);
if(pr > mid) update(pl, pr, rs(p), mid+1, r, d);
push_up(p);
}
ll query_max(ll pl, ll pr, ll p, ll l, ll r){ //query(pl, pr)
if(pl <= l && r <= pr) return maxn[p];
push_down(p, l, r);
ll res = -INF;
if(pl <= mid) res = max(res, query_max(pl, pr, ls(p), l, mid));
if(pr > mid) res = max(res, query_max(pl, pr, rs(p), mid+1, r));
return res;
}
ll query_sum(ll pl, ll pr, ll p, ll l, ll r){ //query(pl, pr)
if(pl <= l && r <= pr) return sumn[p];
push_down(p, l, r);
ll res = 0;
if(pl <= mid) res += query_sum(pl, pr, ls(p), l, mid);
if(pr > mid) res += query_sum(pl, pr, rs(p), mid+1, r);
return res;
}
//-----------------------树链剖分
vector<ll> g[N];
ll depth[N], si[N], son[N], top[N], father[N];
//深度, 子节点数, 重子, 链头, 父节点
ll n, m, s, a, b;
void dfs1(ll u, ll fa){ //求重子
depth[u] = depth[fa] + 1;
father[u] = fa;
si[u] = 1;
for(auto v : g[u]){
if(v != fa){
father[v] = u;
dfs1(v, u);
si[u] += si[v];
if(!son[u] || si[son[u]] < si[v]){
son[u] = v;
}
}
}
}
ll dfn[N];
ll num = 0;
void dfs2(ll u, ll topu){ //建树剖
dfn[u] = ++num;
wnew[num] = w[u];
top[u] = topu;
if(!son[u]) return;
dfs2(son[u], topu);
for(auto v : g[u]){
if(v != father[u] && v != son[u]){
dfs2(v, v);
}
}
}
//-----------------------conbination
void update_range(ll x, ll y, ll z){
while(top[x] != top[y]){
if(depth[top[x]] < depth[top[y]]) swap(x, y);
update(dfn[top[x]], dfn[x], 1, 1, n, z);
x = father[top[x]];
}
if(depth[x] > depth[y]) swap(x, y);
update(dfn[x], dfn[y], 1, 1, n, z);
}
ll query_range_max(ll x, ll y){
ll ans = -INF;
while(top[x] != top[y]){
if(depth[top[x]] < depth[top[y]]) swap(x, y);
ans = max(ans, query_max(dfn[top[x]], dfn[x], 1, 1, n));
x = father[top[x]];
}
if(depth[x] > depth[y]) swap(x, y);
ans = max(ans, query_max(dfn[x], dfn[y], 1, 1, n));
return ans;
}
ll query_range_sum(ll x, ll y){ //同上
ll ans = 0;
while(top[x] != top[y]){
if(depth[top[x]] < depth[top[y]]) swap(x, y);
ans += query_sum(dfn[top[x]], dfn[x], 1, 1, n);
x = father[top[x]];
}
if(depth[x] > depth[y]) swap(x, y);
ans += query_sum(dfn[x], dfn[y], 1, 1, n);
return ans;
}
//-----------------------快乐的主函数
int main(){
memset(maxn, -0x3f, sizeof(maxn));
cin >> n;
for(ll i = 1; i < n; i++){
scanf("%lld %lld", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}
for(ll i = 1; i <= n; i++){
scanf("%lld", &w[i]);
}
dfs1(1, 0);
dfs2(1, 1);
build(1, 1, n);
cin >> m;
ll x, y, z;
string k;
while(m--){
cin >> k;
if(k == "CHANGE") {scanf("%lld%lld", &x, &z); update_range(x, x, z);}
else if(k == "QMAX") {scanf("%lld%lld", &x, &y); printf("%lld\n", query_range_max(x, y));}
else {scanf("%lld%lld", &x, &y); printf("%lld\n", query_range_sum(x, y));}
}
return 0;
}
从 P3384 【模板】重链剖分/树链剖分 来的,仍是沿用的区间修改,但主观认为没有影响……或许罢()