一开始的想法肯定就是按照深度来贪心,选深度最深的 \(k\) 个点,然后发现这样做其实是错误的。
我们发现在此题中,选一个点之前肯定已经把它的所有子树中的节点全部选完了,否则先选择它的子树中的节点答案肯定更优。
然后我们考虑计算出一个节点的贡献:
- 选择了当前节点之后,当前节点 \(i\) 的幸福值为 \(dep_i - 1\)(\(dep_1 = 1\))。
- 但是 \(i\) 的所有子树中的节点答案都会减少 \(1\),因此答案还会减少 \(sz_i - 1\)。
- 因此节点 \(i\) 对答案的贡献就是 \(dep_i - 1 - (sz_i - 1) = dep_i - sz_i\)。
那么我们按照 \(dep_i - sz_i\) 从大到小排序,然后选前 \(k\) 大的加起来就是答案。
注意开 \(\text{long long}\)。
#include <bits/stdc++.h>
#define DEBUG fprintf(stderr, "Passing [%s] line %d\n", __FUNCTION__, __LINE__)
#define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
using namespace std;
typedef long long LL;
typedef pair <int, int> PII;
typedef pair <int, PII> PIII;
inline int gi()
{
int f = 1, x = 0; char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f * x;
}
inline LL gl()
{
LL f = 1, x = 0; char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f * x;
}
const int INF = 0x3f3f3f3f, N = 200003, M = N << 1;
int n, k;
int tot, head[N], ver[M], nxt[M];
int dep[N], sz[N], ans[N];
inline void add(int u, int v)
{
ver[++tot] = v, nxt[tot] = head[u], head[u] = tot;
}
void dfs(int u, int f)
{
dep[u] = dep[f] + 1, sz[u] = 1;
for (int i = head[u]; i; i = nxt[i])
{
int v = ver[i];
if (v == f) continue;
dfs(v, u);
sz[u] += sz[v];
}
ans[u] = dep[u] - sz[u];
}
int main()
{
//File("");
n = gi(), k = gi();
for (int i = 1; i < n; i+=1)
{
int u = gi(), v = gi();
add(u, v), add(v, u);
}
dfs(1, 0);
sort(ans + 1, ans + 1 + n); reverse(ans + 1, ans + 1 + n);
LL sum = 0;
for (int i = 1; i <= k; i+=1) sum += ans[i];
cout << sum << endl;
return 0;
}