树的统计

树根一定要处理QAQ

#include <cstdio>
using namespace std;
int read()
{
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')  f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		x=x*10+c-'0';
		c=getchar();
	}
	return f*x;
}
const int N=1e5+5;
int n,m,father[N],son[N],dep[N],size[N],top[N];
int tre[N*4],sum[N*4],rev[N],seg[N],num,a[N];
int had[N],to[N*2],nxt[N*2],p,a1,b1;
char c[N];
int max(int x,int y)
{
	if(x>y)  return x;
	return y;
}
void swap(int &x,int &y)
{
	x^=y;  y^=x;  x^=y;
}
void add_edge(int x,int y)
{
	nxt[++p]=had[x];
	to[p]=y;
	had[x]=p;
}
void deal_first(int u,int fa)
{
	father[u]=fa;
	size[u]=1;
	dep[u]=dep[fa]+1;
	for(int i=had[u];i;i=nxt[i])
	{
		int v=to[i];
		if(v==fa)  continue;
		deal_first(v,u);
		size[u]+=size[v];
		if(size[v]>size[son[u]])  son[u]=v;
	}
}
void deal_second(int u,int fa)
{
	if(son[u])
	{
		seg[son[u]]=++num;
		rev[num]=son[u];
		top[son[u]]=top[u];
		deal_second(son[u],u);
	}
	for(int i=had[u];i;i=nxt[i])
	{
		int v=to[i];
		if(top[v])  continue;
		seg[v]=++num;
		rev[num]=v;
		top[v]=v;
		deal_second(v,u);
	}
}
void build(int k,int l,int r)
{
	if(l==r)
	{
		tre[k]=sum[k]=a[rev[l]];
		return;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build((k<<1)+1,mid+1,r);
	sum[k]=sum[k<<1]+sum[(k<<1)+1];
	tre[k]=max(tre[k<<1],tre[(k<<1)+1]);
}
void change(int k,int l,int r,int x,int v)
{
	if(l>x||r<x)  return;
	if(l==r&&l==x)
	{
		tre[k]=sum[k]=v;
		return;
	}
	int mid=(l+r)>>1;
	change(k<<1,l,mid,x,v);
	change((k<<1)+1,mid+1,r,x,v);
	sum[k]=sum[k<<1]+sum[(k<<1)+1];
	tre[k]=max(tre[k<<1],tre[(k<<1)+1]);
}
int query_max(int k,int l,int r,int x,int y)
{
	if(r<x||l>y)  return -50000;
	if(l>=x&&r<=y)  return tre[k];
	int mid=(l+r)>>1;
	return max(query_max(k<<1,l,mid,x,y),query_max((k<<1)+1,mid+1,r,x,y));
}
void ask_max(int x,int y)
{
	int fax=top[x],fay=top[y],ans=-50000;
	while(fax!=fay)
	{
		if(dep[fax]<dep[fay])
		{
			swap(x,y);
			swap(fax,fay);
		}
		ans=max(ans,query_max(1,1,num,seg[fax],seg[x]));
		x=father[fax];  fax=top[x];
	}
	if(dep[x]>dep[y])  swap(x,y);
	ans=max(ans,query_max(1,1,num,seg[x],seg[y]));
	printf("%d\n",ans);
}
int query_sum(int k,int l,int r,int x,int y)
{
	if(r<x||l>y)  return 0;
	if(l>=x&&r<=y)  return sum[k];
	int mid=(l+r)>>1,ret=0;
	ret+=query_sum(k<<1,l,mid,x,y);
	ret+=query_sum((k<<1)+1,mid+1,r,x,y);
	return ret;
}
void ask_sum(int x,int y)
{
	int fax=top[x],fay=top[y],ans=0;
	while(fax!=fay)
	{
		if(dep[fax]<dep[fay])
		{
			swap(x,y);
			swap(fax,fay);
		}
		ans+=query_sum(1,1,num,seg[fax],seg[x]);
		x=father[fax];  fax=top[x];
	}
	if(dep[x]>dep[y])  swap(x,y);
	ans+=query_sum(1,1,num,seg[x],seg[y]);
	printf("%d\n",ans);
}
int main()
{
	n=read();
	for(int i=1;i<n;i++)
	{
		a1=read();  b1=read();
		add_edge(a1,b1);
		add_edge(b1,a1);
	}
	for(int i=1;i<=n;i++)  a[i]=read();
	deal_first(1,0);
	num++;
	seg[1]=top[1]=rev[1]=1;
	deal_second(1,0);
	build(1,1,num);
	m=read();
	while(m--)
	{
		scanf("%s",c);
		a1=read();  b1=read();
		if(c[1]=='H')  change(1,1,num,seg[a1],b1);
		if(c[1]=='M')  ask_max(a1,b1);
		if(c[1]=='S')  ask_sum(a1,b1);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值