题目大意:
给你一棵树,问你对于每一个点是否可以在树上删掉一条边,再增加一条边,使它成为树的重心。
tips:一个点成为重心的条件为它的每个子树大小不超过n/2。
解题思路:首先树上问题一般都要转有根树
1.对于一个点它有两个方向:就是向它儿子,就是向它父亲
2.要实现树形dp我们要找到儿子和父亲的关系
3.首先我们发现如果一个节点要是边连出去的子树最多只有一个大于
n
/
2
n/2
n/2
4.如果这个子树的大于
n
/
2
n/2
n/2那么我们就要对这个子树进行操作
5.首先我们要从子树挑除一个最大的并且不超过
n
/
2
n/2
n/2的子树[子树的子树]直接连接到目标点,并且剩下的不能超过
n
/
2
n/2
n/2
通过上面的分析:我们知道我们对于每颗子树要求什么?:
1.首先我们要求出每个子树的大小判断是否大于
n
/
2
n/2
n/2
2.我们要统计子树里面小于n/2的最大的子树是多大
3.设一个down[u]是u节点向下子树中的最大值,up[u]是向上的最大值,在第二次扫描的时候如果父亲方向的siz<n/2的话我们就要更新up[u]
4.其实这里我们可以用一个set去维护每次取最大值
代码:
#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <limits.h>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define hash Hash
#define next Next
#define pb push_back
#define f first
#define s second
#define y1 Y
using namespace std;
const int N = 1e7 + 10, MOD = 1e9 + 7;
const int maxn = 4e5 + 10;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{
read(first);
read(args...);
}
vector<int>G[maxn << 1];
int n;
int maxsiz[maxn << 1];//统计最大的子树在筛选的时候要去除大于n/2的子树
int siz[maxn << 1];//统计siz
int down[maxn << 1], up[maxn << 1];
inline void dfs(int u, int fa)
{
siz[u] = 1;
for(int i = 0; i < G[u].size(); ++ i)
{
int v = G[u][i];
if(v == fa) continue;
dfs(v,u);
siz[u] += siz[v];
down[u] = max(down[u],(siz[v]>n/2)?down[v]:siz[v]);
maxsiz[u] = max(siz[v],maxsiz[u]);
}
return;
}
inline void dfs1(int u, int fa)
{
multiset<int> s;
for(auto it : G[u])
if(it != fa)
s.insert((siz[it]>n/2)?down[it]:siz[it]);
for(auto it :G[u])
{
if(it == fa) continue;
if(n-siz[it]<=n/2) up[it] = max(up[it],n-siz[it]);
else
{
up[it] = max(up[it],up[u]);
s.erase(s.find((siz[it]>n/2)?down[it]:siz[it]));
if(!s.empty()) up[it] = max(up[it],*s.rbegin());
s.insert((siz[it]>n/2)?down[it]:siz[it]);
}
dfs1(it,u);
}
}
int main()
{
read(n);
for(int i = 1; i < n; ++ i)
{
int l, r;
read(l,r);
G[l].pb(r);
G[r].pb(l);
}
dfs(1,0);
dfs1(1,0);
for(int i = 1; i <=n; ++i)
{
int ans = 1;
if(maxsiz[i] > n / 2) ans = maxsiz[i] - down[i] <= n / 2;
if(n - siz[i] > n / 2) ans = n - siz[i] - up[i] <= n / 2;
cout << ans <<" ";
}
return 0;
}