题目描述
一棵树上有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之间。
树链剖分极好的练手题,虽然我调了半小时。。。
链剖是个好东东。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA1(x) b[x].data1
#define DATA2(x) b[x].data2
#define LSIDE(x) b[x].l
#define RSIDE(x) b[x].r
#define MAXN 100010
#define MAX 999999999
using namespace std;
int n,m,c=1,d=1;
int head[MAXN],deep[MAXN],size[MAXN],son[MAXN],top[MAXN],fa[MAXN],id[MAXN];
struct node1{
int next,to;
}a[MAXN<<1];
struct node2{
int data1,data2;
int l,r;
}b[MAXN<<2];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline int max(const int x,const int y){if(x<y)return y;return x;}
void print(){
cout<<endl;
for(int i=1;i<=n;i++)
cout<<deep[i]<<' '<<size[i]<<' '<<son[i]<<' '<<top[i]<<' '<<fa[i]<<' '<<id[i]<<endl;
for(int i=1;i<=4*n;i++)
cout<<DATA1(i)<<' '<<DATA2(i)<<' '<<LSIDE(i)<<' '<<RSIDE(i)<<endl;
cout<<endl;
}
void pushup(int rt){
DATA1(rt)=max(DATA1(LSON),DATA1(RSON));
DATA2(rt)=DATA2(LSON)+DATA2(RSON);
}
void buildtree(int l,int r,int rt){
int mid;
LSIDE(rt)=l;
RSIDE(rt)=r;
if(l==r){
DATA1(rt)=DATA2(rt)=0;
return;
}
mid=l+r>>1;
buildtree(l,mid,LSON);
buildtree(mid+1,r,RSON);
pushup(rt);
}
void update(int l,int r,int c,int rt){
int mid;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
DATA1(rt)=DATA2(rt)=c;
return;
}
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update(l,r,c,LSON);
if(mid<r)update(l,r,c,RSON);
pushup(rt);
}
int query1(int l,int r,int rt){
int mid,ans=-MAX;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)
return DATA1(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans=max(ans,query1(l,r,LSON));
if(mid<r)ans=max(ans,query1(l,r,RSON));
return ans;
}
int query2(int l,int r,int rt){
int mid,ans=0;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)
return DATA2(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans+=query2(l,r,LSON);
if(mid<r)ans+=query2(l,r,RSON);
return ans;
}
void add(int u,int v){
a[c].to=v;
a[c].next=head[u];
head[u]=c++;
a[c].to=u;
a[c].next=head[v];
head[v]=c++;
}
void dfs1(int rt){
son[rt]=0;size[rt]=1;
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(!deep[will]){
deep[will]=deep[rt]+1;
fa[will]=rt;
dfs1(will);
size[rt]+=size[will];
if(size[will]>size[son[rt]])son[rt]=will;
}
}
}
void dfs2(int rt,int f){
id[rt]=d++;top[rt]=f;
if(son[rt])dfs2(son[rt],f);
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will!=son[rt]&&will!=fa[rt])
dfs2(will,will);
}
}
void work1(int x,int y){
update(id[x],id[x],y,1);
return;
}
void work2(int x,int y){
int s=-MAX;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
s=max(s,query1(id[top[x]],id[x],1));
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
s=max(s,query1(id[x],id[y],1));
printf("%d\n",s);
return;
}
void work3(int x,int y){
int s=0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
s+=query2(id[top[x]],id[x],1);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
s+=query2(id[x],id[y],1);
printf("%d\n",s);
return;
}
void work(){
char ch[10];
int x,y;
m=read();
while(m--){
scanf("%s",ch);x=read();y=read();
if(ch[0]=='C')work1(x,y);
if(ch[1]=='M')work2(x,y);
if(ch[1]=='S')work3(x,y);
}
}
void init(){
int u,v,w;
n=read();
for(int i=1;i<n;i++){
u=read();v=read();
add(u,v);
}
deep[1]=fa[1]=1;
dfs1(1);
dfs2(1,1);
buildtree(1,n,1);
for(int i=1;i<=n;i++){
w=read();
update(id[i],id[i],w,1);
}
work();
}
int main(){
init();
return 0;
}