Description
一棵树上有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本身
Input
输入的第一行为一个整数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之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
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 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
Sample Output
4
1
2
2
10
6
5
6
5
16
1
2
2
10
6
5
6
5
16
这题选择了树链剖分来解题。
给大家推荐一个同学推荐给我的树链剖分的好论文:
Code:
#include<bits/stdc++.h>
#define N 30005
using namespace std;
int Ecnt,cnt,root,n,head[N],vis[N];
struct ty{
int next,to;
}E[N*2];
struct ttyy{
int pre,deep,sz,son,tid,top;
}tree[N];
struct lT{
int maxx,sum;
}T[N*4];
void up(int u){
T[u].maxx=max(T[u<<1].maxx,T[u<<1|1].maxx);
T[u].sum=T[u<<1].sum+T[u<<1|1].sum;
}
void add(int u,int v){
E[++Ecnt].next=head[u];
E[Ecnt].to=v;
head[u]=Ecnt;
}
void dfs1(int x,int father,int depth){
vis[x]=1;
tree[x].pre=father;
tree[x].deep=depth;
tree[x].sz=1; tree[x].son=0;
int maxsize=0;
for (int i=head[x];i;i=E[i].next){
int j=E[i].to;
if (vis[j]) continue;
dfs1(j,x,depth+1);
tree[x].sz+=tree[j].sz;
if (tree[j].sz>maxsize){
maxsize=tree[j].sz;
tree[x].son=j;
}
}
}
void dfs2(int x,int ancestor){
vis[x]=1;
tree[x].tid=++cnt;
tree[x].top=ancestor;
if (tree[x].son && (!vis[tree[x].son])) dfs2(tree[x].son,ancestor);
for (int i=head[x];i;i=E[i].next){
int j=E[i].to;
if (vis[j]) continue;
dfs2(j,j);
}
}
void changee(int id,int l,int r,int goal,int num){
if (l==r){
T[id].sum=T[id].maxx=num;
return;
}
int mid=(l+r)>>1;
if (goal<=mid) changee(id<<1,l,mid,goal,num);
else changee(id<<1|1,mid+1,r,goal,num);
up(id);
}
int querysum(int id,int l,int r,int gl,int gr){
if (l>=gl && r<=gr) return T[id].sum;
int mid=(l+r)>>1;
if (gr<=mid) return querysum(id<<1,l,mid,gl,gr); else
if (gl>mid) return querysum(id<<1|1,mid+1,r,gl,gr);
else return querysum(id<<1,l,mid,gl,mid)+querysum(id<<1|1,mid+1,r,mid+1,gr);
}
int querymax(int id,int l,int r,int gl,int gr){
if (l>=gl && r<=gr) return T[id].maxx;
int mid=(l+r)>>1;
if (gr<=mid) return querymax(id<<1,l,mid,gl,gr); else
if (gl>mid) return querymax(id<<1|1,mid+1,r,gl,gr);
else return max(querymax(id<<1,l,mid,gl,mid),querymax(id<<1|1,mid+1,r,mid+1,gr));
}
int solvesum(int u,int v){
int gg=0;
while (tree[u].top!=tree[v].top){
if (tree[tree[u].top].deep<tree[tree[v].top].deep) swap(u,v);
gg+=querysum(1,1,n,tree[tree[u].top].tid,tree[u].tid);
u=tree[tree[u].top].pre;
}
if (tree[u].deep>tree[v].deep) swap(u,v);
gg+=querysum(1,1,n,tree[u].tid,tree[v].tid);
return gg;
}
int solvemax(int u,int v){
int gg=-100000;
while (tree[u].top!=tree[v].top){
if (tree[tree[u].top].deep<tree[tree[v].top].deep) swap(u,v);
gg=max(gg,querymax(1,1,n,tree[tree[u].top].tid,tree[u].tid));
u=tree[tree[u].top].pre;
}
if (tree[u].deep>tree[v].deep) swap(u,v);
gg=max(gg,querymax(1,1,n,tree[u].tid,tree[v].tid));
return gg;
}
int main(){
scanf("%d",&n);
int x,y; Ecnt=0;
for (int i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
root=1; cnt=0;
memset(vis,0,sizeof(vis)); dfs1(root,0,0);
memset(vis,0,sizeof(vis)); dfs2(root,root);
for (int i=1;i<=n;i++){
scanf("%d",&x);
changee(1,1,n,tree[i].tid,x);
}
int m;
scanf("%d",&m);
while (m--){
char s[10];
int x,y;
scanf("%s%d%d",s,&x,&y);
if (s[0]=='C') changee(1,1,n,tree[x].tid,y);
else{
if (s[1]=='M')
printf("%d\n",solvemax(x,y));
else printf("%d\n",solvesum(x,y));
}
}
return 0;
}