题解 CF708C 【Centroids】
考虑当我们已经确定了一棵树的重心并以重心为根,有一个显然的结论,对于任一子节点为根的子树大小一定不超过
因为去掉重心,树所剩下的每个部分一定不超过
因此如果我们以树的重心为根,如果一个点
例如下面这棵树:
以重心
接下来考虑对这棵树进行改造:
我们要在
下面是一种改造过程:
1.删除边
2.添加边
这样,经过改造点
那么,为了令我们当前的点
即我们要在
如果
那么接下来我们要考虑如何计算出
记
考虑
因为我们以重心为根,因此
这样的复杂度是
代码:
#include <iostream>
#include <cstring>
namespace wxy{
const int N = 4e5 + 10;
int size[N],head[N],fail[N << 1],edge[N << 1],tot = 0;
int n,root = 1,ans = 1e9;
bool vis[N];
int d[N][3],f[N];
inline void add(int x,int y){
edge[++tot] = y;
fail[tot] = head[x];
head[x] = tot;
}
inline void insert(int x,int y){add(x,y);add(y,x);}
void dfs_root(int u){
int max_part = 0;
size[u] = 1;
vis[u] = true;
for (int i = head[u];i;i = fail[i]){
int v = edge[i];
if (vis[v]) continue;
dfs_root(v);
size[u] += size[v];
max_part = std::max(max_part,size[v]);
}
max_part = std::max(max_part,n - size[u]);
if (max_part < ans){
ans = max_part;
root = u;
}
}
void dfs_d(int u){
vis[u] = true;
size[u] = 1;
for (int i = head[u];i;i = fail[i]){
int v = edge[i];
if (vis[v]) continue;
dfs_d(v);
size[u] += size[v];
if (size[v] > d[u][0]){
d[u][1] = d[u][0];
d[u][0] = size[v];
}else if (size[v] > d[u][1]){
d[u][1] = size[v];
}
}
}
void dfs_f(int u,int fa){
vis[u] = true;
if (d[fa][0] == size[u]) f[u] = std::max(d[fa][1],f[fa]);
else f[u] = std::max(d[fa][0],f[fa]);
if (n - size[u] <= n / 2) f[u] = std::max(f[u],n - size[u]);
if (u == root) f[u] = 0;
for (int i = head[u];i;i = fail[i]){
int v = edge[i];
if (vis[v]) continue;
dfs_f(v,u);
}
}
void main(){
std::cin >> n;
for (int i = 1; i < n; i++){
int x,y;
std::cin >> x >> y;
insert(x,y);
}
dfs_root(1);
memset(vis,false,sizeof vis);
memset(size,0,sizeof size);
dfs_d(root);
memset(vis,false,sizeof vis);
dfs_f(root,0);
//for (int i = 1; i <= n; i++) std::cout << f[i] << " ";
//std::cout << std::endl;
for (int i = 1; i <= n; i++){
if (size[i] >= n / 2) std::cout << 1 << " ";
else if (n - size[i] - f[i] <= n / 2) std::cout << 1 << " ";
else std::cout << 0 << " ";
}
}
}signed main(){wxy::main();return 0;}