题目描述
一棵树上有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”的形式给出。
输出格式:
对于每个“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
输出样例#1:
4
1
2
2
10
6
5
6
5
16
说明
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
【AC代码】:
#include<bits/stdc++.h>
#define M(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MOD 1000000009
using namespace std;
inline void read(int &x){
char ch=getchar(),c=ch;
x=0;
while(ch<'0' || ch>'9'){
c=ch;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
if(c=='-')x=-x;
}
const int N=31000;
const int M=124000;
int n,m,Summ,Maxx;
int seg[N],rev[M],size[N],son[N],top[N],dep[N];
int sum[M],num[N],father[N],Max[N];
int first[M],next[M],go[M];
void query(int k,int l,int r,int L,int R){
if(L>r || R<l)return;
if(L<=l && r<=R){
Summ+=sum[k];
Maxx=max(Maxx,Max[k]);
return ;
}
int mid=l+r>>1,res=0;
if(mid>=L)query(k<<1,l,mid,L,R);
if(mid+1<=R)query((k<<1)+1,mid+1,r,L,R);
}
void change(int k,int l,int r,int Val,int pos){
if(pos>r || pos<l)return ;
if(l==r && r==pos){
sum[k]=Val;
Max[k]=Val;
return;
}
int mid=l+r>>1;
if(mid>=pos)change(k<<1,l,mid,Val,pos);
if(mid+1<=pos)change((k<<1)+1,mid+1,r,Val,pos);
sum[k]=sum[k<<1]+sum[(k<<1)+1];
Max[k]=max(Max[k<<1],Max[(k<<1)+1]);
}
void dfs1(int u,int f){
int e,v;
size[u]=1;
father[u]=f;
dep[u]=dep[f]+1;
for(e=first[u];v=go[e],e;e=next[e])
if(v!=f){
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]])son[u]=v;
}
}
void dfs2(int u,int f){
int e,v;
if(son[u]){
seg[son[u]]=++seg[0];
top[son[u]]=top[u];
rev[seg[0]]=son[u];
dfs2(son[u],u);
}
for(e=first[u];v=go[e],e;e=next[e])
if(!top[v]){
seg[v]=++seg[0];
rev[seg[0]]=v;
top[v]=v;
dfs2(v,u);
}
}
void build(int k,int l,int r){
int mid=l+r>>1;
if(l==r){
Max[k]=sum[k]=num[rev[l]];
return ;
}
build(k<<1,l,mid);
build((k<<1)+1,mid+1,r);
sum[k]=sum[k<<1]+sum[(k<<1)+1];
Max[k]=max(Max[k<<1],Max[(k<<1)+1]);
}
int tot;
inline void add(int x,int y){
next[++tot]=first[x];
first[x]=tot;
go[tot]=y;
}
inline void insert(int x,int y){
add(x,y);
add(y,x);
}
inline void ask(int x,int y){
int fx=top[x],fy=top[y];
while(fx!=fy){
if(dep[fx]<dep[fy]){
swap(x,y);
swap(fx,fy);
}
query(1,1,seg[0],seg[fx],seg[x]);
x=father[x];
fx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
query(1,1,seg[0],seg[x],seg[y]);
}
int main(){
int i,j,k,x,y;
read(n);
for(i=1;i<n;i++){
read(x),read(y);
insert(x,y);
}
for(i=1;i<=n;i++){
read(x);
num[i]=x;
}
dfs1(1,0);
seg[0]=seg[1]=top[1]=rev[1]=1;
dfs2(1,0);
build(1,1,seg[0]);
read(m);
char sr[10];
int u,v;
for(i=1;i<=m;i++){
cin>>sr+1;
read(u),read(v);
if(sr[1]=='C')change(1,1,seg[0],v,seg[u]);
else{
Summ=0;
Maxx=-1<<30;
ask(u,v);
if(sr[2]=='M')printf("%d\n",Maxx);
else printf("%d\n",Summ);
}
}
}