题解【Codeforces1336A】Linova and Kingdom

题面

一开始的想法肯定就是按照深度来贪心,选深度最深的 (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) 大的加起来就是答案。

注意开 ( ext{long long})

#include <bits/stdc++.h>
#define DEBUG fprintf(stderr, "Passing [%s] line %d
", __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;
}
原文地址:https://www.cnblogs.com/xsl19/p/12740875.html