[BZOJ3631]JLOI2014松鼠的新家|树上差分

看起来是一个裸的树链剖分,其实不用那么麻烦。。给每个点一个标记表示它到root上所有点权值+多少,把每一次将一条链上权值+1的操作差分就相当于把L,R标记+1,把lcafa[lca]标记-1,最后把标记往上传就行了。。

#include<cstdio>
#include<iostream>
#define N 300005
using namespace std;
struct edge{
	int e,xu,next;
}ed[N*4];
int n,i,ne=0,s,e,a[N],A[N],h[N],d[N],pre[N],lca[N],fa[N],u[N];
int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
void adde(int s,int e)
{
	ed[++ne].e=e;ed[ne].next=a[s];a[s]=ne;
}
void addq(int s,int e,int xu)
{
	ed[++ne].e=e;ed[ne].xu=xu;
	ed[ne].next=h[s];h[s]=ne;
}
void dfs(int x)
{
	fa[x]=x;
	for (int j=a[x];j;j=ed[j].next)
		if (ed[j].e!=pre[x])
		{
			pre[ed[j].e]=x;
			dfs(ed[j].e);
			fa[ed[j].e]=x;
			d[x]+=d[ed[j].e];
		}
	u[x]=1;
	for (int j=h[x];j;j=ed[j].next)
		if (u[ed[j].e]) lca[ed[j].xu]=getfa(ed[j].e);
}
void dp(int x)
{
	for (int j=a[x];j;j=ed[j].next)
		if (ed[j].e!=pre[x]) 
			dfs(ed[j].e),d[x]+=d[ed[j].e];
}
int main()
{
	scanf("%d",&n);
	for (i=1;i<=n;i++) a[i]=h[i]=0,fa[i]=i,u[i]=0,d[i]=0;
	for (i=1;i<=n;i++) 
	{
		scanf("%d",&A[i]);
		if (i!=1)addq(A[i],A[i-1],i-1);addq(A[i-1],A[i],i-1);
	}
	for (i=1;i<n;i++) scanf("%d%d",&s,&e),adde(s,e),adde(e,s);
	pre[A[1]]=0;
	dfs(A[1]);
	for (i=1;i<n;i++)
		d[A[i]]++,d[A[i+1]]++,d[lca[i]]--,d[pre[lca[i]]]--;	
	dp(A[1]);
	for (i=2;i<=n;i++) d[A[i]]--;
	for (i=1;i<=n;i++) printf("%d\n",d[i]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值