Codeforces Round #635 (Div. 2) Linova and Kingdom

传送门

考虑贪心,对于所有的旅游地应该靠近根结点,工厂尽可能在叶子结点或者是离根远的地方

假设全部都是工厂,那么答案就是0
那么开始遍历,按照dfs序把点变成旅游点。
如果把深度为d,子树为S的结点变成旅游点,那么除了它外的子树中,所有结点可以结果的旅游地+1,也就是加上S - 1
而对于这个点,因为它的父亲结点都是旅游点,那么贡献值就少了d - 1
那么每个点的贡献值为(S - 1 - (d - 1) = S - d)
那么就把这些值排序,求出前k个最大值和即可

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;
std::vector<int> g[N];
int depth[N], siz[N];
std::vector<int> ans;
void dfs(int u, int fath = 0){
    siz[u] = 1;
    depth[u] = depth[fath] + 1;
    for(auto v : g[u]){
        if(v == fath)continue;
        dfs(v, u);
        siz[u] += siz[v];
    }
    ans.push_back(siz[u] - depth[u]);
}
int main(){
    int n, k;
    cin >> n >> k;
    for(int i = 1; i < n; i++){
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1);
    sort(ans.begin(), ans.end(), greater<int>());
    long long sum = 0;
    for(int i = 0; i < n - k; i++)
        sum += ans[i];
    cout << sum << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/Emcikem/p/12782491.html