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;
}

浙公网安备 33010602011771号