Gym - 102346D Denouncing Mafia 取k叶子节点使叶子到根覆盖节点数最大
给你一棵树 你可以取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); }