0%

树的统计

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成

一些操作:

I. CHANGE u t : 把结点u的权值改为t

II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

III. QSUM u v: 询问从点u到点v的路径上的节点的权值和

注意:从点u到点v的路径上的节点包括u和v本身

输入描述:

输入的第一行为一个整数n,表示节点的个数。接下来n–1行,每行2个整数a和b,表示节点a和节点b之间有

一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作

的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

对于100%的数据,保证 1<=n<=30000, 0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

输出描述:

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

示例1
输入

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

输出

4
1
2
2
10
6
5
6
5
16

shudetongji.cppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<iostream>
#define M 30005
using namespace std;
struct node{
int L,R,sum,mx;
}tree[M<<2];
vector<int>edge[M];
int val[M],A[M],dep[M];
int sz[M];//子树大小
int pathfa[M];//虚边,用于跳向上一条重链
int root[M];//所在重链的根节点
int sonID[M];//重儿子编号
int segID[M];//在线段树上的编号
int sT=0;//线段树编号
int qsum,qmx;
void Assign(int x,int f,int d){//分配重儿子
sz[x]=1;int k=-1; dep[x]=d;
for(int i=0;i<edge[x].size();i++){
int y=edge[x][i];
if(y==f)continue;
Assign(y,x,d+1);
if(k==-1||sz[y]>sz[k])k=y;
sz[x]+=sz[y];
}
sonID[x]=k;
}
void Dfs(int x,int f,int pf){//分配线段树编号
root[x]=f;pathfa[x]=pf;segID[x]=++sT;A[sT]=val[x];
if(sonID[x]!=-1)Dfs(sonID[x],f,pf);
for(int i=0;i<edge[x].size();i++){
int y=edge[x][i];
if(sonID[x]==y||sz[x]<sz[y])continue;//儿子节点和反向边
Dfs(y,y,x);
}
}
void Up(int p){
tree[p].sum=tree[2*p].sum+tree[2*p+1].sum;
tree[p].mx=max(tree[2*p].mx,tree[2*p+1].mx);
}
void build(int L,int R,int p){
tree[p].L=L,tree[p].R=R;
if(L==R){
tree[p].sum=tree[p].mx=A[L];return;
}
int mid=(L+R)>>1;
build(L,mid,2*p);build(mid+1,R,2*p+1);
Up(p);
}
void update(int a,int x,int p){
if(tree[p].L==tree[p].R){
tree[p].mx=tree[p].sum=x;
return;
}
int mid=(tree[p].L+tree[p].R)>>1;
if(a<=mid)update(a,x,2*p);
else update(a,x,2*p+1);
Up(p);
}
void query(int L,int R,int p){
if(tree[p].L==L&&tree[p].R==R){
qsum+=tree[p].sum,qmx=max(qmx,tree[p].mx);
return;
}
int mid=(tree[p].L+tree[p].R)>>1;
if(R<=mid)query(L,R,2*p);
else if(L>mid)query(L,R,2*p+1);
else {
query(L,mid,2*p);query(mid+1,R,2*p+1);
}
}
void Query(int a,int b){
while(root[a]!=root[b]){
if(dep[root[a]]<dep[root[b]])swap(a,b);
query(segID[root[a]],segID[a],1);
a=pathfa[a];//跳到上一条重链
}
if(dep[a]<dep[b])swap(a,b);
query(segID[b],segID[a],1);
}
int main(){
int n,m,i,j,k,a,b;
scanf("%d",&n);
for(i=1;i<n;i++){
scanf("%d %d",&a,&b);
edge[a].push_back(b);
edge[b].push_back(a);
}
for(i=1;i<=n;i++) scanf("%d",&val[i]);
Assign(1,0,1);
Dfs(1,1,0);
build(1,n,1);
scanf("%d",&m);
char tmp[20];
for(i=0;i<m;i++){
scanf("%s%d%d",tmp,&a,&b);
if(tmp[0]=='C'){
update(segID[a],b,1);
}else{
qsum=0,qmx=-10000000;
Query(a,b);
if(tmp[1]=='S')printf("%d\n",qsum);
else printf("%d\n",qmx);
}
}
return 0;
}