CF708C Centroids 的题解
考察:重心、树形 DP。
好题。
钦定
钦定
钦定
我们以 CF 的 test 4 为例。
图中的
我们可以把根定为重心之一,此图中可以定为
考虑把重心换到
因为以原树上的重心为根,则
还有一种情况比较简单,若
但是,我们还需考虑
因为这个情况的研究显然不会再跨过根节点,我们可以直接用子树的大小刻画。
那么设
还应注意,
综上,有方程:
实际上,在实现过程中,有一个经典的 trick:
- 维护最大次大,最小次小,快速解决树形 DP 合并时转移。
具体的,我们令
时间复杂度
::::success[code]
#include<bits/stdc++.h>
#define endl '\n'
//#define MSOD
using namespace std;
using ll = long long;
constexpr ll N = 4e5 + 5;
ll n, ctd, mxx = LLONG_MAX;
ll dp[N], siz[N], mx1[N], mx2[N];
vector<ll> g[N];
inline void dfs_ctd(ll u, ll dad) {
siz[u] = 1;
ll mx = 0;
for(auto v : g[u]) {
if(v == dad) {
continue;
}
dfs_ctd(v, u);
siz[u] += siz[v];
mx = max(mx, siz[v]);
}
mx = max(mx, n - siz[u]);
if(mxx > mx) {
mxx = mx, ctd = u;
}
return;
}
inline void dfs(ll u, ll dad) {
siz[u] = 1;
for(auto v : g[u]) {
if(v == dad) {
continue;
}
dfs(v, u);
siz[u] += siz[v];
if(siz[v] > mx1[u]) {
mx2[u] = mx1[u], mx1[u] = siz[v];
} else if(siz[v] > mx2[u]) {
mx2[u] = siz[v];
}
}
return;
}
inline void dfs1(ll u, ll dad) {
dp[u] = dp[dad];
if(mx1[dad] == siz[u]) {
dp[u] = max(mx2[dad], dp[u]);
} else {
dp[u] = max(mx1[dad], dp[u]);
}
if(n - siz[u] <= n / 2) {
dp[u] = max(dp[u], n - siz[u]);
}
if(u == ctd) {
dp[u] = 0;
}
for(auto v : g[u]) {
if(v == dad) {
continue;
}
dfs1(v, u);
}
return;
}
inline void solve() {
cin>>n;
for(int i = 1 ; i < n ; i ++) {
ll u, v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs_ctd(1, 0);
dfs(ctd, 0);
dfs1(ctd, 0);
for(int i = 1 ; i <= n ; i ++) {
cout<<((siz[i] >= n / 2 || n - siz[i] - dp[i] <= n / 2) ? 1 : 0)<<" ";
}
return;
}
signed main() {
ios::sync_with_stdio(false), cout.tie(0), cin.tie(0);
int TC = 1;
#ifdef MSOD
cin>>TC;
#endif
while(TC --) {
solve();
}
return 0;
}