AIM Tech Round 3 (Div. 1) C. Centroids(树形dp)


C. Centroids

Tree is a connected acyclic graph. Suppose you are given a tree consisting of n vertices. The vertex of this tree is called centroid if the size of each connected component that appears if this vertex is removed from the tree doesn't exceed .

You are given a tree of size n and can perform no more than one edge replacement. Edge replacement is the operation of removing one edge from the tree (without deleting incident vertices) and inserting one new edge (without adding new vertices) in such a way that the graph remains a tree. For each vertex you have to determine if it's possible to make it centroid by performing no more than one edge replacement.

Input

The first line of the input contains an integer n (2 ≤ n ≤ 400 000) — the number of vertices in the tree. Each of the next n - 1 lines contains a pair of vertex indices ui and vi (1 ≤ ui, vi ≤ n) — endpoints of the corresponding edge.

Output

Print n integers. The i-th of them should be equal to 1 if the i-th vertex can be made centroid by replacing no more than one edge, and should be equal to 0 otherwise.

Examples
Input
3
1 2
2 3
Output
1 1 1 
Input
5
1 2
1 3
1 4
1 5
Output
1 0 0 0 0 
Note

In the first sample each vertex can be made a centroid. For example, in order to turn vertex 1 to centroid one have to replace the edge (2, 3) with the edge (1, 3).

         题意:给了一棵树,判断对于每个节点,如果至多修改一条边是否可以使其成为树的重心。

         思路:重心的定义题面上已经给了。对于一个节点,如果要是其成为重心,就是使其每个子树的结点数不超过n/2,因此对于节点数超过n/2的子树,可以找一个其子树(可以是最大子树)使其连到该节点,使这个节点的子树节点数不超过n/2.需要进行两次树形dp:

                   第一次就是从下往上dp,求每个子树的节点数和最大子树(节点数不超过n/2);

                   第二次就是从上往下dp,记录父节点所在子树的最大子树(稍微有点不好搞)。

                   最后就是判断每个节点是否能成为重心。


详细见代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 4*1e5+100;
int ans[maxn];
int num[maxn];
int son[maxn];//记录儿子所在子树的最大子树
int fa[maxn]; //记录父节点所在子树的最大子树
int pre[maxn];
int suf[maxn];
vector<int>v[maxn];
int n;
void dfs(int a,int f)
{
	num[a]=1;
	son[a]=0;
	for(int i=0;i<v[a].size();i++)
	{
		if(v[a][i]==f) continue;
		dfs(v[a][i],a);
		num[a]+=num[v[a][i]];
		son[a]=max(son[a],son[v[a][i]]);
		if(num[v[a][i]]<=n/2) son[a]=max(son[a],num[v[a][i]]);
	}
}
void dfs2(int a,int f)
{
	pre[0]=0;
	for(int i=0;i<v[a].size();i++)
	{
		if(v[a][i]==f)
		{
			pre[i+1]=pre[i];
			continue;
		}
		pre[i+1]=max(pre[i],son[v[a][i]]);
		if(num[v[a][i]]<=n/2) pre[i+1]=max(pre[i+1],num[v[a][i]]);
	}
	int w=0;
	for(int i=v[a].size()-1;i>=0;i--)
	{
		if(v[a][i]==f) continue;
		fa[v[a][i]]=max(w,pre[i]);
		if(f!=-1)
		{
			fa[v[a][i]]=max(fa[v[a][i]],fa[a]);
			if(n-num[a]<=n/2) fa[v[a][i]]=max(fa[v[a][i]],n-num[a]);
		}
		w=max(w,son[v[a][i]]);
		if(num[v[a][i]]<=n/2) w=max(w,num[v[a][i]]);
	}
	for(int i=0;i<v[a].size();i++)
	{
		if(v[a][i]==f) continue;
		dfs2(v[a][i],a);
	}
}
void solve(int a,int f)
{
	ans[a]=1;
	for(int i=0;i<v[a].size();i++)
	{
		if(v[a][i]==f) continue;
		if(num[v[a][i]]>n/2) 
		{
			ans[a]=0;
			if(num[v[a][i]]-son[v[a][i]]<=n/2) ans[a]=1;
		}
		solve(v[a][i],a);
	}
	if(n-num[a]>n/2) 
	{
		ans[a]=0;
		if(n-num[a]-fa[a]<=n/2) ans[a]=1;
	}
}

int main()
{
	scanf("%d",&n);
	int i,j;
	int a,b;
	for(i=1;i<n;i++)
		scanf("%d%d",&a,&b),v[a].push_back(b),v[b].push_back(a);
	dfs(1,-1);
	dfs2(1,-1);
	solve(1,-1);
	for(i=1;i<=n;i++)
		printf("%d%s",ans[i],i==n ? "\n":" ");
	return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值