【BZOJ】【P1036】【ZJOI2008】【树的统计Count】【题解】【树链剖分】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1036

卧槽要注意权值可能为负,所以qmax的时候ans要设成INT_MIn啊啊啊啊

Code:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<climits>
#include<vector>
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define L i<<1
#define R i<<1|1
using namespace std;
int n,m;
const int maxn=30001;
vector<int>G[maxn];
int dep[maxn],son[maxn],siz[maxn],fa[maxn],top[maxn],w[maxn],z=0,a[maxn];
void add(int u,int v){
	G[u].push_back(v);
	G[v].push_back(u);
}
void dfs(int u){
	son[u]=0;siz[u]=1;
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i];
		if(v!=fa[u]){
			dep[v]=dep[u]+1;
			fa[v]=u;
			dfs(v);
			if(siz[v]>siz[son[u]])son[u]=v;
			siz[u]+=siz[v];
		}
	}
}
void build(int u,int tp){
	w[u]=++z;top[u]=tp;
	if(son[u])build(son[u],tp);
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i];
		if(v!=fa[u]&&v!=son[u])
		build(v,v);
	}
}
struct node{
	int sum,Max;
};
struct seg_tree{
	node t[maxn<<2];
	void maintain(int i){
		t[i].sum=t[L].sum+t[R].sum;
		t[i].Max=max(t[L].Max,t[R].Max);
	}
	/*void build(int i,int l,int r){
		if(l>r)return;
		if(l==r){
			t[i].sum=t[i].Max=a[l];
			return;
		}
		int mid=l+r>>1;
		build(lson);build(rson);
		maintain(i);
	}*/
	void change(int i,int l,int r,int p,int x){
		if(l>r)return;
		if(l==r){
			t[i].sum=t[i].Max=x;
			return;
		}
		int mid=l+r>>1;
		if(p<=mid)change(lson,p,x);
		if(p>mid) change(rson,p,x);
		maintain(i);
	}
	int qmax(int i,int l,int r,int l0,int r0){
		if(l>r)return 0;
		if(l0<=l&&r0>=r)
			return t[i].Max;
		int ans=INT_MIN;
		int mid=l+r>>1;
		if(l0<=mid)ans=max(ans,qmax(lson,l0,r0));
		if(r0>mid) ans=max(ans,qmax(rson,l0,r0));
		return ans;
	}
	int qsum(int i,int l,int r,int l0,int r0){
		if(l>r)return 0;
		if(l0<=l&&r0>=r)
			return t[i].sum;
		int ans=0;
		int mid=l+r>>1;
		if(l0<=mid)ans+=qsum(lson,l0,r0);
		if(r0>mid) ans+=qsum(rson,l0,r0);
		return ans;
	}
}T;
void change(int u,int x){
	T.change(1,1,n,w[u],x);
}
void deb(){
	for(int i=1;i<=14;i++)
	printf("#%d sum:%d Max:%d\n",i,T.t[i].sum,T.t[i].Max);
}
int Qmax(int u,int v){
	int ans=INT_MIN;
	while(top[u]!=top[v]){
		if(dep[top[u]]>dep[top[v]]){
			int a=w[u],b=w[top[u]];
			if(a>b)swap(a,b);
			ans=max(ans,T.qmax(1,1,n,a,b));
			u=fa[top[u]];
		}else{
			int a=w[v],b=w[top[v]];
			if(a>b)swap(a,b);
			ans=max(ans,T.qmax(1,1,n,a,b));
			v=fa[top[v]];
		}
	}
	int a=w[u],b=w[v];
	if(a>b)swap(a,b);
	ans=max(ans,T.qmax(1,1,n,a,b));
	return ans;
}
int Qsum(int u,int v){
	int ans=0;
	while(top[u]!=top[v]){
		if(dep[top[u]]>dep[top[v]]){
			int a=w[u],b=w[top[u]];
			if(a>b)swap(a,b);
			ans+=T.qsum(1,1,n,a,b);
			u=fa[top[u]];
		}else{
			int a=w[v],b=w[top[v]];
			if(a>b)swap(a,b);
			ans+=T.qsum(1,1,n,a,b);
			v=fa[top[v]];
		}
	}
	int a=w[u],b=w[v];
	if(a>b)swap(a,b);
	ans+=T.qsum(1,1,n,a,b);
	return ans;	
}
int main(){
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}	
	dfs(1);build(1,1);//T.build(1,1,n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		T.change(1,1,n,w[i],a[i]);
	}
	scanf("%d",&m);	
	int u,v,x;
	//deb();
	while(m--){
		char opt[5];
		scanf("%s",opt);
		if(opt[1]=='H'){//Change	
			scanf("%d%d",&u,&x);
			change(u,x);
		}else
		if(opt[1]=='M'){//QMax
			scanf("%d%d",&u,&v);
			printf("%d\n",Qmax(u,v));
		}else{
			scanf("%d%d",&u,&v);
			printf("%d\n",Qsum(u,v));
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值