题目描述 Description
一棵树上有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本身
输入描述 Input Description
输入文件的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
输出描述 Output Description
对于每个“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
样例输出 Sample Output
4
1
2
2
10
6
5
6
5
16
数据范围及提示 Data Size & Hint
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
链剖裸题。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
using namespace std;
#define filename "count"
const int INF=0x3f3f3f3f;
const int maxn=30005;
struct Edge
{
int to,next;
}edge[maxn<<1];
int head[maxn];
int maxedge;
int n;
inline void addedge(int u,int v)
{
edge[++maxedge]=(Edge){v,head[u]};
head[u]=maxedge;
edge[++maxedge]=(Edge){u,head[v]};
head[v]=maxedge;
}
int val[maxn];
int fa[maxn],son[maxn],size[maxn],depth[maxn];
int top[maxn],id[maxn],rid[maxn],maxnode;
int dfs1(int u,int father,int deep)
{
fa[u]=father,size[u]=1,depth[u]=deep;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==father) continue;
size[u]+=dfs1(v,u,deep+1);
if(!son[u]||size[son[u]]<size[v]) son[u]=v;
}
return size[u];
}
void dfs2(int u,int tp)
{
id[u]=++maxnode;rid[maxnode]=u;top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int mx[maxn<<2],sum[maxn<<2];
inline void update(int node)
{
mx[node]=max(mx[node<<1],mx[node<<1|1]);
sum[node]=sum[node<<1]+sum[node<<1|1];
}
void build(int node,int l,int r)
{
if(l==r)
{
mx[node]=sum[node]=val[rid[l]];
return;
}
int m=(l+r)>>1;
build(node<<1,l,m);
build(node<<1|1,m+1,r);
update(node);
}
inline void init()
{
memset(head,-1,sizeof(head));
maxedge=-1;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
}
for(int i=1;i<=n;i++) scanf("%d",val+i);
dfs1(1,0,1);
dfs2(1,1);
build(1,1,maxnode);
}
void modify(int node,int l,int r,int pos,int v)
{
if(l==r)
{
mx[node]=sum[node]=v;
return;
}
int m=(l+r)>>1;
if(pos<=m) modify(node<<1,l,m,pos,v);
else modify(node<<1|1,m+1,r,pos,v);
update(node);
}
int querymax(int node,int l,int r,int x,int y)
{
if(l==r) return mx[node];
int m=(l+r)>>1;
int max1=-INF,max2=max1;
if(x<=m&&l<=y) max1=querymax(node<<1,l,m,x,y);
if(y>=m+1&&r>=x) max2=querymax(node<<1|1,m+1,r,x,y);
return max(max1,max2);
}
int querysum(int node,int l,int r,int x,int y)
{
if(l==r) return sum[node];
int m=(l+r)>>1;
int sum1=0,sum2=0;
if(x<=m&&l<=y) sum1=querysum(node<<1,l,m,x,y);
if(y>=m+1&&r>=x) sum2=querysum(node<<1|1,m+1,r,x,y);
return sum1+sum2;
}
int FindMax(int u,int v)
{
int t1=top[u],t2=top[v];
int tmp=-INF;
while(t1!=t2)
{
if(depth[t1]<depth[t2]) swap(t1,t2),swap(u,v);//swaped so as to get onto the same greater line
tmp=max(tmp,querymax(1,1,maxnode,id[t1],id[u]));
u=fa[t1];
t1=top[u];
}
if(depth[u]<depth[v]) swap(u,v);//differs u&v
return max(tmp,querymax(1,1,maxnode,id[v],id[u]));
}
int FindSum(int u,int v)
{
int t1=top[u],t2=top[v];
int tmp=0;
while(t1!=t2)
{
if(depth[t1]<depth[t2]) swap(u,v),swap(t1,t2);//C'est le pere pour comparison
tmp+=querysum(1,1,maxnode,id[t1],id[u]);
u=fa[t1];
t1=top[u];
}
if(depth[u]<depth[v]) swap(u,v);
return tmp+querysum(1,1,maxnode,id[v],id[u]);
}
int main()
{
freopen(filename".in","r",stdin);
freopen(filename".out","w",stdout);
init();
int q;
scanf("%d",&q);
char cmd[10];
int x,y;
while(q--)
{
scanf("%s%d%d",cmd,&x,&y);
if(cmd[0]=='C') modify(1,1,maxnode,id[x],y);
else printf("%d\n",cmd[1]=='M'?FindMax(x,y):FindSum(x,y));
}
return 0;
}