•给一棵N个结点数的树;
•M次操作,三种类型:
•(CHANGE u t), 把结点u的权值改为t;
• (QMAX u v), 询问从点u到点v的路径上的节点的最大权值;
• (QSUM u v), 询问从点u到点v的路径上的节点的权值和
线段树只能对链式区间进行维护,而对于树型的维护我们用链式剖分,把树剖分成一条链,然后再用线段树进行维护。
需要具备知识:线段树,二叉树的遍历,链式前向星存图。
线段树和dfs遍历我再这里就不讲了,我就稍微讲下前向星。
这种存图操作需要有 head【】,cnt,和结构体e
struct node
{
int to,next,v;
}e[maxn];
int head[maxn]
to是下一个指向的点,next是下一条边结构体在e【】这个结构体数组的位置 ,head【i】表示 i点相邻的边中最后遍历到的边所在结构体的位置。
void addP(int u,int v)
{
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
cnt初始为0,head【】初始化 -1
dfs1是将f【】(父节点数组) d【】深度,son【】(重儿子)做好
void dfs1(int u,int fa,int depth)//当前点,父节点,深度
{
f[u] = fa;
d[u] = depth;
sz[u] = 1;
for(int i = head[u];i !=-1 ;i = e[i].next){
int v = e[i].to;
if(v == fa) continue;//为了双向连边时防止死循环爆栈
dfs1(v,u,depth + 1);
sz[u] += sz[v];//当前的儿子数维护
if(sz[v] > sz[son[u]]) son[u] = v;//选出最大的儿子为重儿子
}
}
dfs2用来 将top【】(重链头),id【】线段树维护区间 完成好。
void dfs2(int u,int t)//当前点,重链头
{
top[u] = t;
id[u] = ++flag;//将要进行维护的线段树中点的编号
rk[flag] = u;//原来树中的编号
if(!son[u]) return;//到叶子结点直接返回
dfs2(son[u],t);//优先递归重链
for(int i = head[u];i != -1; i = e[i].next){
int v = e[i].to;
if(v != son[u] && v != f[u]) dfs2(v,v);//轻链的top是自己
}
}
下面说下树链剖分的最后步骤
int fsum(int u,int v)
{
int ans = 0;
while(top[u] != top[v]){//两个点不在一个重链上
if(d[top[u]] < d[top[v]]) swap(u,v);//先要维护深度大的点,将深度大的点往上提
ans += querySum(1,id[top[u]],id[u],1,n);
u = f[top[u]];//维护完当前重链后向上提,提到重链头的父节点
}
if(d[u] < d[v]) swap(u,v);//若在一条重链上,直接用线段树进行维护
ans += querySum(1,id[v],id[u],1,n);//深度大的点,id自然就大。L与R要从小到大
return ans;
}
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stdio.h>
#include <ctype.h>
#include <bitset>
#define LL long long
#define ULL unsigned long long
#define mod 10007
#define INF 0x7ffffff
#define mem(a,b) memset(a,b,sizeof(a))
#define MODD(a,b) (((a%b)+b)%b)
using namespace std;
const int maxn = 1e5 + 5;
struct node
{
int to,next,v;
}e[maxn];
int cnt,flag;
int n;
int head[maxn],f[maxn],d[maxn],son[maxn],rk[maxn],id[maxn],top[maxn],sz[maxn];
int sum[maxn << 2],Max[maxn << 2];
void dfs1(int u,int fa,int depth)
{
f[u] = fa;
d[u] = depth;
sz[u] = 1;
for(int i = head[u];i !=-1 ;i = e[i].next){
int v = e[i].to;
if(v == fa) continue;
dfs1(v,u,depth + 1);
sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u,int t)
{
top[u] = t;
id[u] = ++flag;
rk[flag] = u;
if(!son[u]) return;
dfs2(son[u],t);
for(int i = head[u];i != -1; i = e[i].next){
int v = e[i].to;
if(v != son[u] && v != f[u]) dfs2(v,v);
}
}
void pushUp(int rt)
{
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
Max[rt] = max(Max[rt << 1], Max[rt << 1 | 1]);
}
void buildTree(int l,int r,int rt,int pos,int v)
{
if(l == r){
sum[rt] = Max[rt] = v;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) buildTree(l,mid,rt << 1,pos,v);
else buildTree(mid + 1,r,rt << 1 | 1,pos,v);
pushUp(rt);
}
int querySum(int root,int L,int R,int l,int r)
{
int ans = 0;
if(L <= l && r <= R) return sum[root];
int mid = (l + r) >> 1;
if(L <= mid) ans += querySum(root << 1,L,R,l,mid);
if(R > mid) ans += querySum(root << 1 | 1,L,R,mid + 1,r);
return ans;
}
int fsum(int u,int v)
{
int ans = 0;
while(top[u] != top[v]){
if(d[top[u]] < d[top[v]]) swap(u,v);
ans += querySum(1,id[top[u]],id[u],1,n);
u = f[top[u]];
}
if(d[u] < d[v]) swap(u,v);
ans += querySum(1,id[v],id[u],1,n);
return ans;
}
int queryMax(int root,int L,int R,int l,int r)
{
if(L <= l && R >= r) return Max[root];
int mid = (l + r) >> 1;
int ans = -INF;
if(L <= mid) ans = max(ans,queryMax(root << 1,L,R,l,mid));
if(R > mid) ans = max(ans,queryMax(root << 1|1,L,R,mid + 1,r));
return ans;
}
int fMax(int u,int v)
{
int ans = -INF;
while(top[u] != top[v]){
if(d[top[u]] < d[top[v]]) swap(u,v);
ans = max(ans,queryMax(1,id[top[u]],id[u],1,n));
u = f[top[u]];
}
if(d[u] < d[v]) swap(u,v);
ans = max(ans,queryMax(1,id[v],id[u],1,n));
return ans;
}
void addP(int u,int v)
{
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
int main()
{
while(~scanf("%d",&n)){
int u,v;
cnt = flag = 0;
mem(head,-1);
for(int i =0; i < n - 1; i++){
scanf("%d%d",&u,&v);
addP(u,v);
addP(v,u);
}
dfs1(1,0,1);
dfs2(1,1);
for(int i = 1; i <= n; i++){
scanf("%d",&e[i].v);
buildTree(1,flag,1,id[i],e[i].v);
}
int m;
scanf("%d",&m);
while(m--){
char opt[10];
scanf("%s",opt);
if(opt[0] == 'Q' && opt[1] == 'M'){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",fMax(x,y));
}
else if(opt[0] == 'Q' && opt[1] == 'S'){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",fsum(x,y));
}
else if(opt[0] == 'C'){
int x,y;
scanf("%d%d",&x,&y);
buildTree(1,flag,1,id[x],y);
}
}
}
return 0;
}