码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 1036: [ZJOI2008]树的统计Count

时间:2014-05-13 15:45:57      阅读:336      评论:0      收藏:0      [点我收藏+]

标签:bzoj   zjoi   树链剖分   

题目地址:http :// www . lydsy . com / JudgeOnline / problem . php ? id = 1036

题目大意:给出一棵树,每个点有一个权值,要求三种操作:1.修改某个点的权值,2.询问x到y路径上各点的权值最大值,3.询问x到y路径上各点的权值之和。

算法讨论:树链剖分模板题。

Code:

#include <cstdio>
#include <algorithm>

#define N 30000
#define oo 0x7f7f7f7f

using namespace std;

int n,x,y,tot,q,mm,w[N+10],next[N*2+10],son[N+10],ed[N*2+10],fa[N+10],deep[N+10],size[N+10],heavy[N+10],tree1[N*4+10],tree2[N*4+10],head[N+10],id[N+10],num[N+10];
bool vis[N+10];
char s[10];

void add(int x,int y){
	next[++mm]=son[x];
	son[x]=mm;
	ed[mm]=y;
}

void dfs1(int x){
	vis[x]=1;
	size[x]=1;
	for (int i=son[x];i;i=next[i]){
		int y=ed[i];
		if (!vis[y]){
			fa[y]=x;
			deep[y]=deep[x]+1;
			dfs1(y);
			size[x]+=size[y];
			if (size[y]>size[heavy[x]]) heavy[x]=y;
		}
	}
}

void dfs2(int x){
	vis[x]=1;
	id[x]=++tot;
	num[tot]=x;
	if (!head[x]) head[x]=x;
	if (heavy[x]) head[heavy[x]]=head[x],dfs2(heavy[x]);
	for (int i=son[x];i;i=next[i]){
		int y=ed[i];
		if (!vis[y]) dfs2(y);
	}
}

void up(int k){
	tree1[k]=max(tree1[k*2],tree1[k*2+1]);
	tree2[k]=tree2[k*2]+tree2[k*2+1];
}

void build(int k,int lc,int rc){
	if (lc==rc){
		tree1[k]=tree2[k]=w[num[lc]];
		return;
	}
	int mid=(lc+rc)/2;
	build(k*2,lc,mid);
	build(k*2+1,mid+1,rc);
	up(k);
}

void change(int k,int lc,int rc,int x,int y){
	if (lc==rc){
		tree1[k]=tree2[k]=y;
		return;
	}
	int mid=(lc+rc)/2;
	if (x<=mid) change(k*2,lc,mid,x,y);
	else change(k*2+1,mid+1,rc,x,y);
	up(k);
}

int query1(int k,int lc,int rc,int l,int r){
	if (l==lc && r==rc) return tree1[k];
	int mid=(lc+rc)/2;
	if (r<=mid) return query1(k*2,lc,mid,l,r);
	if (l>mid) return query1(k*2+1,mid+1,rc,l,r);
	return max(query1(k*2,lc,mid,l,mid),query1(k*2+1,mid+1,rc,mid+1,r));
}

int query2(int k,int lc,int rc,int l,int r){
	if (l==lc && r==rc) return tree2[k];
	int mid=(lc+rc)/2;
	if (r<=mid) return query2(k*2,lc,mid,l,r);
	if (l>mid) return query2(k*2+1,mid+1,rc,l,r);
	return query2(k*2,lc,mid,l,mid)+query2(k*2+1,mid+1,rc,mid+1,r);
}

int qmax(int x,int y){
	int ans=-oo;
	while (head[x]!=head[y]){
		if (deep[head[x]]<deep[head[y]]) swap(x,y);
		ans=max(ans,query1(1,1,tot,id[head[x]],id[x]));
		x=fa[head[x]];
	}
	if (deep[x]>deep[y]) swap(x,y);
	ans=max(ans,query1(1,1,tot,id[x],id[y]));
	return ans;
}

int qsum(int x,int y){
	int ans=0;
	while (head[x]!=head[y]){
		if (deep[head[x]]<deep[head[y]]) swap(x,y);
		ans+=query2(1,1,tot,id[head[x]],id[x]);
		x=fa[head[x]];
	}
	if (deep[x]>deep[y]) swap(x,y);
	ans+=query2(1,1,tot,id[x],id[y]);
	return ans;
}

int main(){
	scanf("%d",&n);
	for (int i=1;i<n;++i){
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	for (int i=1;i<=n;++i) scanf("%d",&w[i]);
	dfs1(1);
	for (int i=1;i<=n;++i) vis[i]=0;
	dfs2(1);
	build(1,1,tot);
	scanf("%d",&q);
	for (int i=1;i<=q;++i){
		scanf("%s%d%d",s,&x,&y);
		if (s[0]==‘C‘) change(1,1,tot,id[x],y);
		else if (s[0]==‘Q‘ && s[1]==‘M‘) printf("%d\n",qmax(x,y));
		else printf("%d\n",qsum(x,y));
	}
	return 0;
}

By Charlie Pan

Mar 12,2014




BZOJ 1036: [ZJOI2008]树的统计Count,布布扣,bubuko.com

BZOJ 1036: [ZJOI2008]树的统计Count

标签:bzoj   zjoi   树链剖分   

原文地址:http://blog.csdn.net/charlie_pyc/article/details/25652453

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!