CF708C Centroids

给定一颗树,你有一次将树改造的机会,改造的意思是删去一条边,再加入一条边,保证改造后还是一棵树。

请问有多少点可以通过改造,成为这颗树的重心?

考虑一次$dp$。
$dp[x]$表示$x$子树内不超过$n/2$的最大子树的大小。

$ans=(siz[maxsiz[x]]-dp[maxsiz[x]])\leq n/2$

显然不能直接每个暴力。

考虑换根$dp$

$h[x]$表示外子树的子树里不超过$n/2$的最大子树的大小。

判断的时候再加上外子树的大小即可。

考虑如何维护$h[x]$

$if(n - siz[x] > n / 2)$那么所需要要的一定再外子树上,$h[to]=max(h[x],dp[x]去掉dp[to]$),

$if(n - siz[x] <= n / 2)$那么$x$的外子树就是最大的$h[x]$,$h[to]=max(n-siz[x],dp[x]去掉dp[to]$),

$dp[x]$去掉$dp[to]$搞个最大值和次大值。

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mk make_pair
const int N = 1e6 + 10;
const int mod = 1e9 + 7;

int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0', c = getchar();
return x * f;
}
vector<int> g[N];
int n;
pii dp[N];
int siz[N], ms[N];
void cmax(pii &o, ll x)
{
if (x >= o.first)
{
o.second = o.first;
o.first = x;
}
else if (x >= o.second)
{
o.second = x;
}
}
int v[N];
void dfs(int x, int fa)
{
dp[x] = mk(0, 0);
siz[x] = 1;

for (int to : g[x])
{
if (to == fa)
continue;
dfs(to, x);
siz[x] += siz[to];
if (siz[ms[x]] < siz[to])
ms[x] = to;
if (siz[to] > n / 2)
{

cmax(dp[x], dp[to].first);
if (dp[x].first == dp[to].first)
v[x] = to;
}
else
{
cmax(dp[x], siz[to]);
if (dp[x].first == siz[to])
v[x] = to;
}
}
}
int ans[N];
int c[N];
void dfs1(int x, int fa)
{
ans[x] = 1;
if (siz[ms[x]] > n / 2)
ans[x] = (siz[ms[x]] - dp[ms[x]].first <= n / 2);
else if (n - siz[x] > n / 2)
ans[x] = (n - siz[x] - c[x] <= n / 2);
for (int to : g[x])
{
if (to == fa)
continue;
int cur = (n - siz[x] <= n / 2) ? (n - siz[x]) : c[x];
c[to] = max(c[to], cur);
if (to == v[x])
c[to] = max(c[to], dp[x].second);
else
c[to] = max(c[to], dp[x].first);

dfs1(to, x);
}
}
int main()
{
n = read();
for (int i = 1; i < n; i++)
{
int u = read(), v = read();
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
dfs1(1, 0);
for (int i = 1; i <= n; i++)
{

printf("%d ", ans[i]);
}
}