码迷,mamicode.com
首页 > 其他好文 > 详细

【XSY2407】【CF708C】Centroids 树形DP

时间:2021-04-05 12:25:59      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:add   span   个数   连通块   最大的   题目   ons   连通   using   

题目描述
我们定义一个点\(x\)是整棵树的重心(总共有\(n\)个点)当且仅当删掉点x后所有连通块的大小都不超过\(n/2\)。我们定义一次操作为删掉一条边再加上一条边,必须满足操作后整个图还是一棵树。给你一棵\(n\)个点的树,求每个点能否在一次操作后成为重心。

输入
第一行一个整数\(n\)
接下来\(n-1\)行每行两个整数\(u\)\(v\):表示第\(u\)个点与第\(v\)个点间有一条边。

输出
\(1\)\(n\)个数:第\(i\)个数表示第\(i\)个点能否在一次操作后成为重心。(若可以则输出\(1\),若不可以则输出\(0\)
样例输入
3
1 2
2 3

样例输出
1 1 1

样例解释
样例1:我们可以删掉边\((2,3)\),然后加上边\((1,3)\),这样第一个点就可以成为重心。

数据范围
\(2?≤?n?≤?400?000\)
\(1≤u_i,v_i≤n\)

如果这个树本来就是重心,那么肯定可以成为重心。
如果一个树不是重心,那么一定有一颗子树它的重量\(≥n/2\),我们当然要把这个子树拆掉一部分。
拆掉之后装在哪里呢,当然就是判断当前的点上啊。
对于当前拆掉的那一部分,我们肯定要求它\(≤n/2\)不然还不是重心。
于是我们有\(f[x]\)表示\(f[x]\)的子树中满足\(≤n/2\)的最大的子树。
对于一个点,我们在判断的时候判一下把子树移出来是否满足即可。
当然他父亲的的子树的信息要第二次\(dfs\)时候处理。
如果当前处理的子树正好是他父亲的\(f\)值所在的子树,我们当然要取父亲的次小值。
于是对于每个点,我们只要存下\(f\),次小\(f\),\(siz\)

#include<bits/stdc++.h>
 
 
using namespace std;
 
const int N=4e6+10;
 
int n, cnt, head[N], siz[N];
int maxson[N], f[N][2], h[N], g[N], ans[N];
 
struct EDGE {
    int y, nex;
} edge[N<<1];
 
void add(int x, int y) {
    edge[++cnt].y=y;
    edge[cnt].nex=head[x];
    head[x]=cnt++;
}
 
void dfs1(int x, int fa) {
    siz[x]=1;
    for(int i=head[x]; i; i=edge[i].nex) {
        int y=edge[i].y;
        if(y==fa) continue;
        dfs1(y, x);
        siz[x]+=siz[y];
        if(siz[y]>siz[maxson[x]]) maxson[x]=y;
        int cur = (siz[y] <= n / 2) ? siz[y] : f[y][0];
        if(cur > f[x][0]) {
            f[x][1] = f[x][0];
            f[x][0] = cur;
            g[x] = y;
        } else if(cur > f[x][1])
            f[x][1] = cur;
    }
}
 
void dfs2(int x, int fa) {
    ans[x]=true;
    if(siz[maxson[x]]>n/2)
        ans[x] = (siz[maxson[x]]-f[maxson[x]][0]<=n/2);
    else if(n-siz[x]>n/2)
        ans[x]=(n-siz[x]-h[x]<=n/2);
    for(int i=head[x]; i; i=edge[i].nex) {
        int y=edge[i].y;
        if(y==fa) continue;
        int cur=(n-siz[x]<=n/2)?(n-siz[x]):h[x];
        h[y]=max(h[y], cur);
        h[y]=max(h[y], f[x][g[x]==y]);
        dfs2(y, x);
    }
}
 
int main() {
    scanf("%d", &n);
    for(int i=1; i<n; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y), add(y, x);
    }
    dfs1(1, 0), dfs2(1, 0);
    for(int i=1; i<=n; i++) printf("%d ", ans[i]);
}

【XSY2407】【CF708C】Centroids 树形DP

标签:add   span   个数   连通块   最大的   题目   ons   连通   using   

原文地址:https://www.cnblogs.com/2017gdgzoi1164/p/14613201.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!