codeforces-1335-C Linova and Kingdom

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\n",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\n", sum);
    return 0;
}

 

posted @ 2020-04-16 11:30  L·S·D  阅读(321)  评论(0编辑  收藏  举报