Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Solution
裸♂的树链剖分
根据定义我们把边分成轻重边,然后映射到线段树上。根据证明可以知道重边一定是相邻的,而且任意一点到根的路径上最多有 log2n 条非连续的轻重边,那么像lca一样跳一跳线段树查询一下就行了
Code
#include <stdio.h>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define erg(i, st) for (int i = ls[st]; i; i = e[i].next)
#define INF 0x3f3f3f3f
#define N 50001
#define E N * 11 + 1
struct edge{int x, y, next;}e[E];
struct treeNode{int l, r, mx, sum;}t[N * 5 + 1];
int size[N], pos[N], bl[N], ls[N], fa[N], dep[N], g[N], cnt;
inline void addEdge(int &cnt, int x, int y){
cnt += 1; e[cnt] = (edge){x, y, ls[x]}; ls[x] = cnt;
}
inline void dfs1(int now){
size[now] = 1;
erg(i, now){
if (e[i].y ^ fa[now]){
fa[e[i].y] = now;
dep[e[i].y] = dep[now] + 1;
dfs1(e[i].y);
size[now] += size[e[i].y];
}
}
}
inline void dfs2(int now, int up){
pos[now] = ++ cnt;
bl[now] = up;
int mx = 0;
erg(i, now){
if (dep[e[i].y] > dep[now] && size[e[i].y] > size[mx]){
mx = e[i].y;
}
}
if (!mx){
return;
}
dfs2(mx, up);
erg(i, now){
if (dep[e[i].y] > dep[now] && e[i].y != mx){
dfs2(e[i].y, e[i].y);
}
}
}
inline int max(int x, int y){
return x>y?x:y;
}
inline int queryMx(int now, int l, int r){
if (t[now].l == l && t[now].r == r){
return t[now].mx;
}
int mid = (t[now].l + t[now].r) >> 1;
if (r <= mid){
return queryMx(now << 1, l, r);
}else if (l > mid){
return queryMx(now << 1 | 1, l, r);
}else{
return max(queryMx(now << 1, l, mid), queryMx(now << 1 | 1, mid + 1, r));
}
}
inline int querySum(int now, int l, int r){
if (t[now].l == l && t[now].r == r){
return t[now].sum;
}
int mid = (t[now].l + t[now].r) >> 1;
if (r <= mid){
return querySum(now << 1, l, r);
}else if (l > mid){
return querySum(now << 1 | 1, l, r);
}else{
return querySum(now << 1, l, mid) + querySum(now << 1 | 1, mid + 1, r);
}
}
inline void modify(int now, int l, int r, int v){
if (t[now].l == t[now].r){
t[now].mx = t[now].sum = v;
return;
}
int mid = (t[now].l + t[now].r) >> 1;
if (r <= mid){
modify(now << 1, l, r, v);
}else if (l > mid){
modify(now << 1 | 1, l, r, v);
}else{
modify(now << 1, l, mid, v);
modify(now << 1 | 1, mid + 1, r, v);
}
t[now].mx = max(t[now << 1].mx, t[now << 1 | 1].mx);
t[now].sum = t[now << 1].sum + t[now << 1 | 1].sum;
}
inline void swap(int &x, int &y){
x ^= y;
y ^= x;
x ^= y;
}
inline int getMx(int x, int y){
int mx = -INF;
while (bl[x] ^ bl[y]){
if (dep[bl[x]] < dep[bl[y]]){
swap(x, y);
}
mx = max(mx, queryMx(1, pos[bl[x]], pos[x]));
x = fa[bl[x]];
}
if (pos[x] > pos[y]){
swap(x, y);
}
mx = max(mx, queryMx(1, pos[x], pos[y]));
return mx;
}
inline int getSum(int x, int y){
int sum = 0;
while (bl[x] ^ bl[y]){
if (dep[bl[x]] < dep[bl[y]]){
swap(x, y);
}
sum += querySum(1, pos[bl[x]], pos[x]);
x = fa[bl[x]];
}
if (pos[x] > pos[y]){
swap(x, y);
}
sum += querySum(1, pos[x], pos[y]);
return sum;
}
inline void build(int now, int l, int r){
t[now] = (treeNode){l, r, 0, 0};
if (l == r){
return;
}
int mid = (l + r) >> 1;
build(now << 1, l, mid);
build(now << 1 | 1, mid + 1, r);
}
int main(void){
int n;
scanf("%d", &n);
int edgeCnt = 0;
rep(i, 1, n - 1){
int x, y;
scanf("%d%d", &x, &y);
addEdge(edgeCnt, x, y);
addEdge(edgeCnt, y, x);
}
rep(i, 1, n){
scanf("%d", &g[i]);
}
cnt = 0;
dfs1(1);
dfs2(1, 1);
build(1, 1, n);
rep(i, 1, n){
modify(1, pos[i], pos[i], g[i]);
}
int m;
scanf("%d", &m);
rep(i, 1, m){
int x, y;
char ch[10];
scanf("%s%d%d", ch, &x, &y);
if (ch[0] == 'C'){
modify(1, pos[x], pos[x], y);
}else if (ch[1] == 'M'){
int prt = getMx(x, y);
printf("%d\n", prt);
}else if (ch[1] == 'S'){
int prt = getSum(x, y);
printf("%d\n", prt);
}
}
return 0;
}