codeforces-1335-C Linova and Kingdom
传送门:https://codeforces.com/contest/1337/problem/C
题意:有一颗n个节点的树,每个节点代表一个城市,让你选择k个城市,使这几个城市到根节点的路上 经过的不是这k个节点的节点数最多 求这k个点到根结点路上经过的总结点数
qswl,昨天也不知道怎么搞得就是错,同一个思路,今天换了一种写法,也不知道怎么就对了……
有被自己蠢到
因为要这个路上经过的总结点数最大,如果路上可以经过这k个节点,那就是按照深度排序,从深了往浅了加k个数 答案是sum
但这个题不能把这k个数包含在内,那这个节点的贡献就不是他的深度了
就比如样例3,如果5属于这k个数,那他堵了4的路 他的贡献就是他的深度-1
如果7属于这k个数,那他堵了4 8 5 3 的路(因为贪心7属于k那么8 4 3 5 必然属于k ) 他的贡献就是他的深度-4
我们发现,减掉的数就是以他为根的子树的大小
所以用一个结构体存下 深度和子树的大小 贡献=深度-子树大小
再按照贡献的大小排序,取前k大
sum应该是要开long long
#include <bits/stdc++.h> using namespace std; #define ll long long const int mod = 1e9 + 7; const int inf = 0x3f3f3f3f; const int maxn = 1000009; vector<int> ve[200009]; bool vis[200009]; int cnt = 0; struct node { int ans;//深度 int root;//以他为根的子树的大小 } x[200009]; int cmp(node a, node b) { return a.ans > b.ans; } void dfs(int n, int pre) { x[n].ans = x[pre].ans+1;//深度+1 x[n].root=1; vis[n] = 1; int l = ve[n].size(); for (int i = 0; i < l; i++) { if (!vis[ve[n][i]]) { dfs(ve[n][i],n); x[n].root+=x[ve[n][i]].root; } } } int main() { int n, k, u, v; scanf("%d%d", &n, &k); for (int i = 1; i < n; i++) { scanf("%d%d", &u, &v); ve[u].push_back(v); ve[v].push_back(u); } dfs(1, 0); // for(int i=1;i<=n;i++) printf("%d %d ",x[i].ans,x[i].root); for(int i=1;i<=n;i++) x[i].ans=x[i].ans-x[i].root;//x[i]的贡献 sort(x + 1, x + 1 + n, cmp); ll sum = 0; for (int i = 1; i <= k; i++) { sum += x[i].ans;//取前k个 } printf("%lld ", sum); return 0; }