题目大意
一棵树上有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本身
数据范围 1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
1树链剖分(相对简单,不打算讲)。
2动态树
用splay维护max值和sum值。
对于查询操作u到v路径的max值或sum值
(若u的深度<v的深度则swap(u,v))
,
先access(u),再access(v),access(v)的过程中最后一个维护的点即是lca(u,v),因为access(u)后,u和lca已在同一tree中,且树的父亲(树中深度最小的点的父亲)为null,
所以access(v)处理到lca后便会结束。求max值,答案max(max[u],key[lca],max[tree[lca][1]]),因为执行access(v)后,u和lca的树边便会断开,又u是树中深度最大的点,所以max[u]是u到lca的路径(不包括lca)中的max值,
同理可得max[tree[lca][1]]是lca到v的路径(不包括lca)中的max值。
求sum值,类似的做法。
修改操作,先access(u),把u旋到树顶,然后修改w[u]=t。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#define inf INT_MAX
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=30000+5;
int tree[maxn][2],fa[maxn],pfa[maxn],key[maxn],num[maxn],sum[maxn],lca,next[maxn*2],f[maxn],g[maxn*2],cnt,d[maxn];
int i,j,n,m;
void add(int x,int y){
next[++cnt]=f[x];
f[x]=cnt;g[cnt]=y;
}
void update(int x){
num[x]=max(key[x],max(num[tree[x][0]],num[tree[x][1]]));
sum[x]=key[x]+sum[tree[x][0]]+sum[tree[x][1]];
}
int pd(int x){
if (tree[fa[x]][0]==x) return 0;else return 1;
}
void rotate(int x){
int y=fa[x],z=pd(x);
fa[x]=fa[y];
if (fa[y]) tree[fa[y]][pd(y)]=x;else
pfa[x]=pfa[y],pfa[y]=0;
tree[y][z]=tree[x][1-z];
if (tree[x][1-z]) fa[tree[x][1-z]]=y;
tree[x][1-z]=y;
fa[y]=x;
update(y);
}
void splay(int x){
while (fa[x]!=0){
int y=fa[x];
if (fa[y]!=0)
if (pd(x)==pd(y)) rotate(y);else rotate(x);
rotate(x);
}
update(x);
}
void access(int u){
int v=0;
while (u){
splay(u);
fa[tree[u][1]]=0;pfa[tree[u][1]]=u;
tree[u][1]=v;fa[v]=u;
pfa[v]=0;
update(u);
v=u,u=pfa[u];
}lca=v;
}
void ch(int x,int y){
access(x);
splay(x);
pfa[x]=y;
}
void dfs(int x,int y){
int i=f[x];
while (i>0){
if (g[i]!=y) ch(g[i],x),d[g[i]]=d[x]+1,dfs(g[i],x);
i=next[i];
}
}
int main(){
key[0]=num[0]=-inf;
scanf("%d",&n);
fo(i,1,n-1) {
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}dfs(1,0);
fo(i,1,n) scanf("%d",&key[i]);
scanf("%d",&m);
fo(i,1,m){
char c=getchar();int x,y;
while ((c<'A')||(c>'Z')) c=getchar();
if (c=='Q') {
fo(j,1,3) c=getchar();
scanf("%d%d",&x,&y);
if (d[x]<d[y]) swap(x,y);
if (x==y){
printf("%d\n",key[x]);
continue;
}
access(x);
lca=y,access(y);
splay(x);
int ans;
if (c=='X'){
ans=num[x];
if (lca==y) ans=max(ans,key[y]);else
ans=max(ans,max(key[lca],num[tree[lca][1]]));
}else{
ans=sum[x];
if (lca==y) ans=ans+key[y];else
ans=ans+key[lca]+sum[tree[lca][1]];
}
printf("%d\n",ans);
}else{
fo(j,1,5) c=getchar();
scanf("%d%d",&x,&y);
access(x);
splay(x);
key[x]=y;
update(x);
}
}
}