这题非常简单,但我赛时看了一眼觉得不太好写就放一边了。
干完 D 题之后回来一眼切了,怎么评价。
一个比较显然的做法是枚举中心点,这里把它叫做 $u$。
然后观察到可以枚举 $y$ 是多少,然后确定有多少个 $v$ 满足存在边 $(u,v)$ 并且 $deg_v - 1 \geq y$。
这里 $deg_v$ 表示 $v$ 的度数。
对于一个确定的 $y$,显然把所有 $deg_v - 1 \geq y$ 的点 $v$ 都加进来是不劣的,假设有 $c$ 个这样的点,那么雪花树上就有 $1 + c + c \times (deg_v - 1) = 1 + c \times deg_v$($u$ 本身加上 $v$ 数量加上 $v$ 儿子的数量)。
然后发现枚举 $u$ 再枚举 $y$ 显然是不可行的。但是 $\geq y$ 这个东西一眼就很后缀和,树状数组维护就好了。
好像所有学长和学弟都写了一个神秘排序?看不懂,我觉得树状数组挺显然的。
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 15, M = N << 1;
int n, h[N], e[M], ne[M], idx = 0;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int tr[N], deg[N];
void change(int x, int d) {
for ( ; x ; x -= x & -x) tr[x] += d;
}
int query(int x) {
int res = 0;
for ( ; x < N; x += x & -x) res += tr[x];
return res;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) h[i] = -1;
for (int i = 1, u, v; i < n; i++) {
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
deg[u]++, deg[v]++;
}
long long ans = 0;
for (int u = 1; u <= n; u++) {
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
change(deg[v], 1);
}
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
// if (u == 2) cout << deg[v] << ' ' << query(deg[v]) << ' ' << 1 + query(deg[v]) * 1ll * deg[v] << endl;
ans = max(ans, 1 + query(deg[v]) * 1ll * deg[v]);
}
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
change(deg[v], -1);
}
}
printf("%lld\n", n - ans);
return 0;
}