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

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值