Gym - 102346D Denouncing Mafia 取k叶子节点使叶子到根覆盖节点数最大

旧城冷巷雨未停 提交于 2019-12-02 16:28:52

给你一棵树 你可以取K条链 一条链为根到叶子的路径 问你K条链最多覆盖树上多少个节点

贪心的做 肯定是每次取最长链 但是取完最长链 一颗树就会变为若干个森林 我们要维护当前所有森林里的最长链

ans数组记录当前节点子树里的最长链长为多少 dfs到一个节点 就把除了最长链上的儿子的ans全部push到q里(这里可以维护一个最大值来优化掉优先队列qq)

然后最后把ans[1] push到q里 取最大的k个即可

为什么这么做是正确的 因为优先队列q里存的是每个节点的父亲节点去掉最长链后自己当根节点时子树的最长链长度

我们每次贪心就是从若干个森林里取出最长链最长的哪条消掉 所以直接取q的前k个即可

#include<bits/stdc++.h>
using namespace std;
vector<int> g[100005];
int ans[100005];
priority_queue<int> q;
void dfs(int x) {
        priority_queue<int> qq;
        ans[x] = 1;
        for (int v : g[x]) {
                dfs(v);
                qq.push(ans[v]);
        }
        if (g[x].size()) {
                ans[x] = qq.top() + 1;
                qq.pop();
                while (qq.size()) {
                        q.push(qq.top());
                        qq.pop();
                }
        }
}
int main() {
        int n, k, x;
        scanf("%d %d", &n, &k);
        for (int i = 2; i <= n; i++) {
                scanf("%d", &x);
                g[x].push_back(i);
        }
        int anser = 0;
        dfs(1);
        q.push(ans[1]);
        while (k--&&q.size()) {
                anser += q.top();
                q.pop();
        }
        printf("%d\n", anser);
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!