[ZJOI2008]树的统计
[ZJOI2008]树的统计
=
题目描述
一棵树上有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”的操作,每行输出一个整数表示要求输出的结果。
说明
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节 点的权值w在-30000到30000之间。
解法
-
一到树剖裸题,套个线段树轻松AC(如果不会树剖[戳我](http://www.cnblogs.com/ljq-despair/p/8639462.html))
代码
-
```
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define rg register
#define mid ((l+r)>>1)
#define lc no<<1
#define rc no<<1|1
#define ls lc,l,mid
#define rs rc,mid+1,r
using namespace std;
il int gi(){
rg char a=getchar();rg int b=0,f=1;
while((a<'0'||a>'9')&&a!='-')a=getchar();
if(a=='-')f=-1,a=getchar();
while(a>='0'&&a<='9')b=b*10+a-'0',a=getchar();
return b*f;
}
const int N=1e6;
int a[N],nex[N],to[N],w[N],dfn[N],fa[N],top[N],son[N],size[N],sum[N],ma[N],n,q,cnt;
void dfs1(int u){
int s=0;
size[u]=1;
for(int i=a[u];i;i=nex[i]){
int v=to[i];
if(v==fa[u])continue;
fa[v]=u;
dfs1(v);
size[u]+=size[v];
if(size[v]>s)son[u]=v,s=size[v];
}
}
void dfs2(int u,int TOP){
top[u]=TOP;dfn[u]=++cnt;
if(son[u])dfs2(son[u],TOP);
for(int i=a[u];i;i=nex[i]){
int v=to[i];
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
void pushup(int no){sum[no]=sum[lc]+sum[rc];ma[no]=max(ma[lc],ma[rc]);}
void build(int no,int l,int r){
if(l==r){
sum[no]=ma[no]=w[l];
return ;
}
build(ls);build(rs);
pushup(no);
}
void update(int no,int l,int r,int u,int x){
if(l==r){sum[no]=ma[no]=x;return ;}
if(u<=mid)update(ls,u,x);
else update(rs,u,x);
pushup(no);
}
int query1(int no,int l,int r,int L,int R){
if(l>=L&&r<=R)return sum[no];
if(l>R||r<L)return 0;
return query1(ls,L,R)+query1(rs,L,R);
}
int query2(int no,int l,int r,int L,int R){
if(l>=L&&r<=R)return ma[no];
if(r<L||l>R)return -1e9;
return max(query2(ls,L,R),query2(rs,L,R));
}
int main(){
n=gi();
for(int i=1,t=0;i<n;++i){
int u=gi(),v=gi();
nex[++t]=a[u],to[t]=v,a[u]=t;
nex[++t]=a[v],to[t]=u,a[v]=t;
}
dfs1(1);dfs2(1,1);
for(int i=1;i<=n;++i)w[dfn[i]]=gi();
q=gi();
build(1,1,n);
while(q--){
char op=getchar();
while(op!='C'&&op!='Q')op=getchar();
if(op=='C'){int u=gi(),t=gi();update(1,1,n,dfn[u],t);}
if(op=='Q'){
op=getchar();int u=gi(),v=gi();
if(op=='M'){
int ans=-1e9;
while(top[u]!=top[v]){
if(dfn[u]<dfn[v])swap(u,v);
ans=max(ans,query2(1,1,n,dfn[top[u]],dfn[u]));
u=fa[top[u]];
}
if(dfn[u]>dfn[v])swap(u,v);
ans=max(ans,query2(1,1,n,dfn[u],dfn[v]));
printf("%d\n",ans);
}
if(op=='S'){
int ans=0;
while(top[u]!=top[v]){
if(dfn[u]<dfn[v])swap(u,v);
ans+=query1(1,1,n,dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
if(dfn[u]>dfn[v])swap(u,v);
ans+=query1(1,1,n,dfn[u],dfn[v]);
printf("%d\n",ans);
}
}
}
return 0;
}
```