QQ联系我

BZOJ 1036: [ZJOI2008]树的统计Count

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB

Submit: 18937  Solved: 7731

[Submit][Status][Discuss]

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

  输入的第一行为一个整数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

Sample Output

4
1
2
2
10
6
5
6
5
16

题解

裸的树链剖分

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
using namespace std;
const int N=30005,inf=0x3f3f3f3f;
int n,k=1,cnt,q;
int head[N],w[N],fa[N],son[N],dep[N],tot[N],t[N],pre[N],top[N],sum[N<<2],mx[N<<2];
struct edge{
	int u,v,next;
}e[N<<1];
void addedge(int u,int v){
	e[k]=(edge){u,v,head[u]};
	head[u]=k++;
}
void insert(int u,int v){
	addedge(u,v);
	addedge(v,u);
}
void dfs1(int u){
	int v;
	dep[u]=dep[fa[u]]+1;
	tot[u]=1;
	for(int i=head[u];i;i=e[i].next){
		v=e[i].v;
		if(v==fa[u])continue;
		fa[v]=u;
		dfs1(v);
		tot[u]+=tot[v];
		if(!son[u]||tot[v]>tot[son[u]])son[u]=v;
	}
}
void dfs2(int u,int f){
	top[u]=f;
	t[u]=++cnt;
	pre[cnt]=u;
	if(!son[u])return;
	dfs2(son[u],f);
	int v;
	for(int i=head[u];i;i=e[i].next){
		v=e[i].v;
		if(v==son[u]||v==fa[u])continue;
		dfs2(v,v);
	}
}
void pushup(int u){
	sum[u]=sum[u<<1]+sum[u<<1|1];
	mx[u]=max(mx[u<<1],mx[u<<1|1]);
}
void build(int u,int l,int r){
	if(l==r){
		sum[u]=w[pre[l]];
		mx[u]=w[pre[l]];
		return;
	}
	int mid=(l+r)>>1;
	build(lson);
	build(rson);
	pushup(u);
}
void update(int u,int l,int r,int a,int x){
	if(l==r){
		sum[u]=x;
		mx[u]=x;
		return;
	}
	int mid=(l+r)>>1;
	if(a<=mid)update(lson,a,x);
	else update(rson,a,x);
	pushup(u);
}
int query_max(int u,int l,int r,int a,int b){
	int ret=-inf;
	if(l>=a&&r<=b)return mx[u];
	int mid=(l+r)>>1;
	if(a<=mid)ret=max(ret,query_max(lson,a,b));
	if(b>mid)ret=max(ret,query_max(rson,a,b));
	return ret;
}
int query_sum(int u,int l,int r,int a,int b){
	int ret=0;
	if(l>=a&&r<=b)return sum[u];
	int mid=(l+r)>>1;
	if(a<=mid)ret+=query_sum(lson,a,b);
	if(b>mid)ret+=query_sum(rson,a,b);
	return ret;
}
int get_max(int u,int v){
	int ret=-inf;
	int fu=top[u],fv=top[v];
	while(fu!=fv){
		if(dep[fu]<dep[fv]){
			swap(u,v);
			swap(fu,fv);
		}
		ret=max(ret,query_max(1,1,n,t[fu],t[u]));
		u=fa[fu],fu=top[u];
	}
	if(dep[u]>dep[v])swap(u,v);
	ret=max(ret,query_max(1,1,n,t[u],t[v]));
	return ret;
}
int get_sum(int u,int v){
	int ret=0;
	int fu=top[u],fv=top[v];
	while(fu!=fv){
		if(dep[fu]<dep[fv]){
			swap(u,v);
			swap(fu,fv);
		}
		ret+=query_sum(1,1,n,t[fu],t[u]);
		u=fa[fu],fu=top[u];
	}
	if(dep[u]>dep[v])swap(u,v);
	ret+=query_sum(1,1,n,t[u],t[v]);
	return ret;
}
int main(){
	scanf("%d",&n);
	int a,b;
	for(int i=1;i<=n-1;i++){
		scanf("%d%d",&a,&b);
		insert(a,b);
	}
	for(int i=1;i<=n;i++)scanf("%d",&w[i]);
	dfs1(1);
	dfs2(1,1);
	build(1,1,n);
	scanf("%d",&q);
	int u,v;
	char ch[10];
	for(int i=1;i<=q;i++){
		scanf("%s%d%d",ch,&u,&v);
		if(ch[1]=='H')update(1,1,n,t[u],v);
		else if(ch[1]=='M')printf("%d\n",get_max(u,v));
		else if(ch[1]=='S')printf("%d\n",get_sum(u,v));
	}
	return 0;
}
posted @ 2017-10-17 15:12  czy020202  阅读(113)  评论(0编辑  收藏  举报