CF 708C:Centroids

题目传送口

题意:

定义:如果一个节点的所有子树大小都小于 n/2,称这个节点为 Centroids
我们可以对树进行一次操作,切掉一个路径,并将切掉的部分接到另一个节点,问那些节点可以成为 Centroids

思路:(思路来源:b站@董晓算法)

我们将树的一个点当成总的根节点,对于一个点 u,如果我们要判断其是否能成为 Centroids,需要有几个信息:以 u 为根的子树(后面写为 u 树)一共有多少个点,子数中不大于 n / 2 的最大子树,次大子树,u 树外的不大于 n / 2 的最大子树,有这些信息后,我们就可以进行判断:
如果 u 树大于 n / 2,判断 u 树减去其小于 n / 2 的最大数是否会满足条件
如果(n - u树) 大于 n / 2,判断(n - u树)- u 树外的不大于 n / 2 的最大子树是否会满足条件

实现过程见代码(,也可以点上面的链接看视频)

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;
const int N = 400010;
vector<int> e[N]; 
int sz[N], f[N], m1[N], m2[N], n, g[N], ans[N];
void dfs1(int u, int fa){
    sz[u] = 1;
    for(auto s : e[u]){
        if(s == fa) continue;
        dfs1(s, u);
        sz[u] += sz[s];
        
        if(sz[s] > sz[m1[u]]) m2[u] = m1[u], m1[u] = s;
        else if(sz[s] > sz[m2[u]]) m2[u] = s;
        f[u] = max(f[u], f[s]);
    }
    if(sz[u] <= (n >> 1)) f[u] = sz[u];
}
void dfs2(int u, int fa){
    for(auto s : e[u]){
        if(s == fa) continue;
        if(n - sz[s] <= (n >> 1)) g[s] = n - sz[s];
        else if(s != m1[u]) g[s] = max(g[u], f[m1[u]]);
        else g[s] = max(g[u], f[m2[u]]);
        dfs2(s, u);
    }
    if(sz[u] > (n >> 1)){
        ans[u] = (sz[m1[u]] - f[m1[u]] <= (n >> 1));
    }else
        ans[u] = (n - sz[u] - g[u] <= (n >> 1));
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;
    for(int i = 1;i < n;i ++){
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dfs1(1, 0);
    dfs2(1, 0);
    for(int i = 1;i <= n;i ++) cout << ans[i] << ' ';
    return 0;
}
posted @ 2025-03-19 15:40  ter_rave  阅读(32)  评论(0)    收藏  举报