codeforces 709E 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 

题意:

给出一棵树,要求你最多改变一条边,看这个点能否成为重心;

思路:

树形dp,先转化成有根树,第一次dfs先找到每个节点以下的节点数目和能切断的最多的数目以及最多和次多转移来的节点,第二次dfs就是找答案了;
由于一个那个超过n/2的子树只有一棵,要么来自当前节点的子节点,要么来自父节点,所以在树上进行转移;具体的看代码注释;

AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bits/stdc++.h>
#include <stack>
#include <map>
 
using namespace std;
 
#define For(i,j,n) for(int i=j;i<=n;i++)
#define mst(ss,b) memset(ss,b,sizeof(ss));
 
typedef  long long LL;
 
template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
    for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
    if(!p) { puts("0"); return; }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + '0');
    putchar('\n');
}
 
const LL mod=1e9+7;
const double PI=acos(-1.0);
const int inf=1e9;
const int N=4e5+10;
const int maxn=1e3+20;
const double eps=1e-12;


int n,siz[N],ans[N],submax[N],max1[N],max2[N];
vector<int>ve[N];

void dfs(int cur,int fa)
{
    siz[cur]=1;//节点数目
    submax[cur]=0;//submax[cur]是以cur为根的子树能切掉的最大的节点数目,
    int len=ve[cur].size();
    for(int i=0;i<len;i++)
    {
        int x=ve[cur][i];
        if(x==fa)continue;
        dfs(x,cur);
        siz[cur]+=siz[x];
        if(submax[x]>submax[cur])
        {
            max2[cur]=max1[cur];//max2[cur]记录次大,max1[cur]记录最大;
            max1[cur]=x;
            submax[cur]=submax[x];
        }
        else if(submax[x]>submax[max2[cur]])max2[cur]=x;
    }
    if(siz[cur]<=n/2)submax[cur]=siz[cur];
}
void dfs1(int cur,int fa,int mmax)
{
    int len=ve[cur].size(),flag=1;
    for(int i=0;i<len;i++)
    {
        int x=ve[cur][i];
        if(x==fa)//父节点转移过来
        {
            int temp=n-siz[cur];
            if(temp>n/2&&temp-mmax>n/2)flag=0;
            continue;
        }
        if(siz[x]>n/2)//子节点转移过来
        {
            if(siz[x]-submax[x]>n/2)flag=0;
        }
    }
    ans[cur]=flag;
    for(int i=0;i<len;i++)
    {
        int x=ve[cur][i];
        if(x==fa)continue;
        int temp;
        if(n-siz[x]<=n/2)temp=n-siz[x];
        else 
        {
            if(max1[cur]==x)temp=max(mmax,submax[max2[cur]]);//如果x正好是最大的转移过来的就取mmax和次大的最大值
            else temp=max(mmax,submax[max1[cur]]);//否则取mmax与最大的最大值
        }
        dfs1(x,cur,temp);
    }
}
int main()
{
    read(n);
    int u,v;
    For(i,1,n-1)
    {
        read(u);read(v);
        ve[v].push_back(u);
        ve[u].push_back(v);
    }
    dfs(1,0);
    dfs1(1,0,0);
    for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    return 0;
}

  




posted @ 2016-08-25 21:56  LittlePointer  阅读(793)  评论(0编辑  收藏  举报