AIM Tech Round 3 (Div. 2) E. Centroids (树形dp)

E. Centroids
time limit per test
4 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

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).

题意:规定一个树上操作:删掉一个树边,这样会变成两棵树,然后把其中一棵的断点接到另一棵树上的任何一个节点上。问你对于树上每一个节点,能不能通过最多一次的修改操作,把该点变为树的重心。如果该点可以就输出1,否则输出0。

题解:枚举每个节点作为根,那么这个节点的子树中,如果只有一个大于n/2,那么就从这个子树中抽取一个最大的不超过n/2的子树,然后接到当前根,如果这个子树还是大于n/2,或者还有子树大于n/2,那么这两种情况是不可以的。

dfs_down跑一遍,把每个节点u为根的其中一棵子树大小dw跑出来,然后跑出来以u为根的一子树中不超n/2的最大的子树,再max一下大小。

dfs_up跑一遍,把另外一棵子树up也跑出来。然后再枚举每个节点的子树,再与n/2比较一下就可以啦。

代码:

#pragma comment(linker, "/STACK:102400000,102400000")
//#include<bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
#include <utility> 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define mst(a) memset(a, 0, sizeof(a))
#define M_P(x,y) make_pair(x,y)
#define in freopen("in.txt","r",stdin) 
#define rep(i,j,k) for (int i = j; i <= k; i++)  
#define per(i,j,k) for (int i = j; i >= k; i--)  
#define lson x << 1, l, mid  
#define rson x << 1 | 1, mid + 1, r  
const int lowbit(int x) { return x&-x; }  
const double eps = 1e-8;  
const int INF = 1e9+7; 
const ll inf =(1LL<<62) ;
const int MOD = 1e9 + 7;  
const ll mod = (1LL<<32);
const int N =1e6+6; 
const int M=100010;
const int maxn=1001; 
template <class T1, class T2>inline void getmax(T1 &a, T2 b) {if (b>a)a = b;}  
template <class T1, class T2>inline void getmin(T1 &a, T2 b) {if (b<a)a = b;}
int read(){
int v = 0, f = 1;char c =getchar();
while( c < 48 || 57 < c ){if(c=='-') f = -1;c = getchar();}
while(48 <= c && c <= 57) v = v*10+c-48, c = getchar();
return v*f;}
int n;
int sz[N],par[N];
int up[N], dw[N]; //两棵子树 
vector<int> adj[N]; //邻接矩阵 
void dfs_sz(int v, int p =-1)
{
    par[v] = p;
    sz[v] = 1;
    for(auto u : adj[v])
    {
        if (u != p){
        	dfs_sz(u,v);
			sz[v] += sz[u];
		}           
    }        
}
void dfs_down(int v, int p = -1) //一子树 
{
    dw[v] = (sz[v] <= n / 2 ? sz[v]: 0);
    for (auto u : adj[v])  
    {
        if(u != p)
        {
        	dfs_down(u,v);
		    dw[v] = max(dw[v],dw[u]);
		}           
    }      
}
void dfs_up(int v, int val = 0, int p = -1) //二子树 
{
    up[v] = max((n - sz[v] <= n / 2 ? n - sz[v]: 0), val);
    int mx0 = 0, mx1 = 0;
    for(auto u : adj[v])
    {
        if(u != p)
        {
            if(dw[u] >= mx0){
            	mx1 = mx0;
			    mx0 = dw[u];
			}             
            else if(dw[u] >= mx1){
            	mx1 = dw[u];
			}                
        }
    }       
    for (auto u : adj[v])
    {
        if(u != p)
        {
            dfs_up(u, max(up[v], mx0 == dw[u] ? mx1 : mx0), v);
        }
    }      
}
int main()
{   
	int u,v;
    cin>>n;
    for(int i=0;i<n-1;i++)
    {      
        cin>>u>>v;
        --u, --v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    dfs_sz(0);
    dfs_down(0);
	dfs_up(0); 
	 
    for(int v = 0; v < n; v++)  //枚举每个节点u作为根
    {
        int ans = 1;
        for(auto u : adj[v]) 
        {
            if(u == par[v])  
            {
                if (n - sz[v] - up[v] > n / 2) 
                    ans = 0;
            } 
            else
            {
                if(sz[u] - dw[u] > n / 2)
                    ans = 0;
            }
        }
        cout <<ans<<' ';
    }
    return 0; 
}


  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值