Codeforces 1336A Linova and Kingdom【贪心】

题目

Writing light novels is the most important thing in Linova's life. Last night, Linova dreamed about a fantastic kingdom. She began to write a light novel for the kingdom as soon as she woke up, and of course, she is the queen of it.

There are n cities and n-1 two-way roads connecting pairs of cities in the kingdom. From any city, you can reach any other city by walking through some roads. The cities are numbered from 1 to n, and the city 1 is the capital of the kingdom. So, the kingdom has a tree structure.

As the queen, Linova plans to choose exactly k cities developing industry, while the other cities will develop tourism. The capital also can be either industrial or tourism city.

A meeting is held in the capital once a year. To attend the meeting, each industry city sends an envoy. All envoys will follow the shortest path from the departure city to the capital (which is unique).

Traveling in tourism cities is pleasant. For each envoy, his happiness is equal to the number of tourism cities on his path.

In order to be a queen loved by people, Linova wants to choose k cities which can maximize the sum of happinesses of all envoys. Can you calculate the maximum sum for her?

Input

The first line contains two integers n and k (2\le n\le 2 \cdot 10^5, 1\le k< n) — the number of cities and industry cities respectively.

Each of the next n-1 lines contains two integers u and v (1\le u,v\le n), denoting there is a road connecting city u and city v.

It is guaranteed that from any city, you can reach any other city by the roads.

Output

Print the only line containing a single integer — the maximum possible sum of happinesses of all envoys.

题目大意

给你一棵 n 个节点的树,让你将其中恰好 K 个节点染成黑色,其余染成白色

总答案为每一个黑色节点到1号节点路径上的白色节点个数之和,问你答案最大是多少

题解

首先想到 O(n\log^2n) 的树剖暴力做法:初始每个节点的价值为其深度,每当一个节点变成黑色节点,则将它到1号根节点路径上的所有节点价值-1。不断选择价值最大的节点染为黑色即可

然而这肯定不是正解,所以咕了......下面是正经做法

首先有结论:如果一个节点为黑色节点,则它的子树中全为黑色节点

证明:假设一个黑色节点的子树中有一个白色节点,则将这两个节点交换颜色,一定会使答案更优

所以做法就是:一个节点 x 的价值定义为 dep[x]-(siz[x]-1),即自身贡献减去子节点个数。不断地在当前的叶子节点中,选择价值最大的点,将其价值加入答案,摘去叶子,并更新叶子节点集合,重复操作 K 次即可。复杂度 O(n\log n)

Code

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
#define MAX_N 200005
#define pii pair<int, int>
#define int long long

using namespace std;

int n, K, ans = 0;
int dep[MAX_N];
int siz[MAX_N];
int cnt[MAX_N];
vector<int> e[MAX_N];
priority_queue<pii> q;

void dfs(int x, int p, int d) {
    dep[x] = d, siz[x] = 1;
    for (int i = 0; i < e[x].size(); i++) {
        int t = e[x][i];
        if (t != p) {
            dfs(t, x, d + 1);
            siz[x] += siz[t];
        }
    }
}

signed main() {
    scanf("%lld%lld", &n, &K);
    int x, y;
    for (int i = 1; i < n; i++) {
        scanf("%lld%lld", &x, &y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dfs(1, 0, 0);
    for (int i = 1; i <= n; i++) {
        cnt[i] = (i == 1 ? e[i].size() : e[i].size() - 1);
        if (!cnt[i]) {
            q.push(pii(dep[i], i));
        }
    }
    for (int i = 1; i <= K; i++) {
        pii p = q.top();
        q.pop(), x = p.second, ans += p.first;
        for (int j = 0; j < e[x].size(); j++) {
            int t = e[x][j];
            cnt[t]--;
            if (!cnt[t]) {
                q.push(pii(dep[t] - (siz[t] - 1), t));
            }
        }
    }
    printf("%lld\n", ans);
}
点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注