51nod3116 松鼠的新家

3116 松鼠的新家

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。

松鼠想邀请小熊前来参观,并且还指定一份参观指南,他希望小熊能够按照他的指南顺序,先去 a_{1},再去 a_{2},……,a_{n}最后到 ,去参观新家。可是这样会导致重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。

小熊是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。

因为松鼠参观指南上的最后一个房间a_{n}是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

输入

第一行一个正整数n,表示房间个数
第二行n个正整数a1,a2,......,an
接下来n-1行,每行两个整数x,y,表示标号为x和y的房间有树枝相连

输出

一共 n 行,第 i 行输出标号为 i 的房间至少需要放多少个糖果,才能让小熊有糖果吃。

数据范围

10% 2 <= n <= 10
30% 2 <= n <= 4000
100% 2 <= n <= 300000

输入样例

输入样例1:
5
1 4 5 3 2
1 2
2 4
2 3
4 5
输入样例2:
10
1 2 3 4 5 6 7 8 9 10
1 10
1 2
1 3
2 4
2 6
3 5
3 7
8 6
5 9

输出样例

输出样例1:
1
2
1
2
1
输出样例2:
9
7
7
1
3
3
1
1
1
0

解析:

对树上的点维护一个点权,如果可以做到每次给a[i-1]到a[i]树上路径上的点的权值+1,那么最终每个点的点权值就是至少要放的糖果数,而树上差分恰恰可以做这样的事情。

我们记a[i],a[i-1]的最近公公祖先为z,那么我们的树上路径一定是a[i-1]先到z,再从z到a[i]。

那么我们就利用树上差分,先对a[i-1]到z路径上的点(除z外)点权+1,再对a[i]到z路径上的点(除z外)的点权+1,但是这时z的点权还没被加,因此我们还要对z到z路径上的点的点权+1

给一个点到它祖先路径上的点权加上一个数c是树上差分的基本操作,具体来说,如果点权差分数组为w,那么如果我们要对x到z路径上的点(除z外)+1,则w[x]++,w[z]--。最后通过统计每个点子树的w权值和求得每个点的点权。

放代码:

#include<bits/stdc++.h>
using namespace std;
#define maxn 300010
struct node
{
	int size,dfn,son,top,fa,dep;
}tr[maxn];
int s[maxn];
int qz[maxn];
int a[maxn],n;
int rnk[maxn],cnt=0;
inline int read()
{
	register int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c<='9'&&c>='0')
	{
		x=(x<<3)+(x<<1)+(c^48);
		c=getchar();
	}
	return x*f;
}
int len=0;
int last[maxn];
struct edge{int x,y,next;}e[maxn*2];
void ins(int x,int y)
{
	len++;
	e[len]={x,y,last[x]};
	last[x]=len;
}
void dfs1(int x)
{
	tr[x].size=1;
	for(int i=last[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(!tr[y].size)
		{
			dfs1(y);
			tr[x].size+=tr[y].size;
			if(!tr[x].son||tr[tr[x].son].size<tr[y].size)
				tr[x].son=y;
		}
	}
}
void dfs2(int x,int top,int fa)
{
	cnt++;
	tr[x].dfn=cnt;
	rnk[cnt]=x;
	tr[x].top=top;
	tr[x].fa=fa;
	tr[x].dep=tr[fa].dep+1;
	if(!tr[x].son)return;
	dfs2(tr[x].son,top,x);
	for(int i=last[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(y!=tr[x].son&&y!=tr[x].fa)dfs2(y,y,x);
	}
}
void qwq(int x,int y)
{
	while(tr[x].top!=tr[y].top)
	{
		if(tr[tr[x].top].dep>tr[tr[y].top].dep)
		{
			s[tr[tr[x].top].dfn]++,s[tr[x].dfn+1]--;
			x=tr[tr[x].top].fa;
		}
		else
		{
			s[tr[tr[y].top].dfn]++,s[tr[y].dfn+1]--;
			y=tr[tr[y].top].fa;
		}
	}
	x=tr[x].dfn;
	y=tr[y].dfn;
	if(x>y)swap(x,y);
	s[x]++;s[y+1]--;
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
	}
	int x,y;
	for(int i=1;i<n;i++)
	{
		x=read();y=read();
		ins(x,y);
		ins(y,x);
	}
	dfs1(1);
	dfs2(1,1,1);
	for(int i=2;i<=n;i++)
	{
		qwq(a[i-1],a[i]);
		s[tr[a[i]].dfn]--;
		s[tr[a[i]].dfn+1]++;
	}
	for(int i=1;i<=n;i++)
	{
		s[i]+=s[i-1];
		qz[rnk[i]]=s[i];
	}
	for(int i=1;i<=n;i++)
	{
		printf("%d\n",qz[i]);
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/ZCH1901/article/details/120097464