题解:P2590 [ZJOI2008] 树的统计

思路

重链剖分板子题,用线段树维护剖分过的线性结构即可。

AC代码

#include<bits/stdc++.h>
#define ll long long
#define re register int
using namespace std;

const int maxn=30005;
const int inf=0x3f3f3f3f;

inline ll read()
{
	ll x=0,f=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
	return x*f;
}

ll tot=0;

ll w[maxn],b[maxn],d[maxn],fa[maxn];
ll siz[maxn],son[maxn],id[maxn],top[maxn];

struct node
{
	ll nex,to;
}e[maxn<<1];ll head[maxn<<1],cnt=0;

struct dd
{
	ll l,r,sum,maxx;
}t[maxn<<2];

inline void add(ll x,ll y)
{
	e[++cnt].to=y;
	e[cnt].nex=head[x];
	head[x]=cnt;
}

inline void dfs1(ll x,ll f,ll deep)
{
	siz[x]=1;
	d[x]=deep;
	fa[x]=f;
	for(re i=head[x];i;i=e[i].nex)
	{
		ll y=e[i].to;
		if(y==f)continue;
		dfs1(y,x,deep+1);
		siz[x]+=siz[y];
		if(siz[son[x]]<siz[y])
		{
			son[x]=y;
		}
	}
	return;
}

inline void dfs2(ll x,ll top_)
{
	id[x]=++tot;
	b[tot]=w[x];
	top[x]=top_;
	if(!son[x])return;
	dfs2(son[x],top_);
	for(re i=head[x];i;i=e[i].nex)
	{
		ll y=e[i].to;
		if(!id[y])dfs2(y,y);
	}
	return;
}

inline void push_up(ll x)
{
	t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
	t[x].maxx=max(t[x<<1].maxx,t[x<<1|1].maxx);
}

inline void build(ll x,ll l,ll r)
{
	t[x].l=l;t[x].r=r;
	if(l==r)
	{
		t[x].sum=b[l];
		t[x].maxx=b[l];
		return;
	}
	ll mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	push_up(x);
	return;
}

inline void tree_change(ll x,ll l,ll r,ll q,ll v)
{
	if(l==r)
	{
		t[x].sum=t[x].maxx=v;
		return;
	}
	ll mid=(l+r)>>1;
	if(q<=mid)tree_change(x<<1,l,mid,q,v);
	else tree_change(x<<1|1,mid+1,r,q,v);
	push_up(x);
}

inline ll querysum(ll x,ll l,ll r)
{
	ll ans=0;
	if(l<=t[x].l&&r>=t[x].r)
	{
		return t[x].sum;
	}
	ll mid=(t[x].l+t[x].r)>>1;
	if(l<=mid)ans+=querysum(x<<1,l,r);
	if(r>mid)ans+=querysum(x<<1|1,l,r);
	return ans;
}

inline ll querymax(ll x,ll l,ll r)
{
	ll ans=-inf;
	if(l<=t[x].l&&r>=t[x].r)return t[x].maxx;
	ll mid=(t[x].l+t[x].r)>>1;
	if(l<=mid)ans=max(ans,querymax(x<<1,l,r));
	if(r>mid)ans=max(ans,querymax(x<<1|1,l,r));
	return ans;
}

inline ll tree_sum(ll u,ll v)
{
	ll ans=0;
	while(top[u]!=top[v])
	{
		if(d[top[u]]<d[top[v]])swap(u,v);
		ans+=querysum(1,id[top[u]],id[u]);
		u=fa[top[u]];
	}
	if(d[u]>d[v])swap(u,v);
	ans+=querysum(1,id[u],id[v]);
	return ans;
}

inline ll tree_max(ll u,ll v)
{
	ll ans=-inf;
	while(top[u]!=top[v])
	{
		if(d[top[u]]<d[top[v]])swap(u,v);
		ans=max(ans,querymax(1,id[top[u]],id[u]));
		u=fa[top[u]];
	}
	if(d[u]>d[v])swap(u,v);
	ans=max(ans,querymax(1,id[u],id[v]));
	return ans;
}

ll n,m;

int main()
{
    // freopen("test.in","r",stdin);
	// freopen("test.out","w",stdout);
	n=read();
	int x,y;
	for(re i=1;i<n;i++)
	{
		x=read();y=read();
		add(x,y);add(y,x);
	}
	for(re i=1;i<=n;i++)w[i]=read();

	dfs1(1,0,1);
	dfs2(1,1);
	build(1,1,n);

	m=read();

	for(re i=1;i<=m;i++)
	{
		char a[10];
		cin>>a;
		x=read();y=read();
		if(a[1]=='H')
		{
			tree_change(1,1,n,id[x],y);
		}
		else if(a[1]=='M')
		{
			printf("%lld\n",tree_max(x,y));
		}
		else if(a[1]=='S')
		{
			printf("%lld\n",tree_sum(x,y));
		}
	}

	return 0;
}
posted @ 2025-03-02 20:40  Zheng_iii  阅读(11)  评论(0)    收藏  举报