Linova and Kingdom

题意:

从一颗 (n) 个节点的树上,选择 (k) 个点,要求从这些点到根节点 (1) 的路径上经过的非选中的点的个数的总和最大。
数据范围:(2≤n≤2⋅10^5, 1≤k<n)

传送门

分析:

  从深度和子树大小去考虑。
  首先,基于贪心的策略,优先选择深度大的点。对于一个点,如果选择该点,那么其子树中的所有点肯定均被选择了。考虑选择该点会最后的总和产生什么影响,首先会加上该点的深度,然后子树中所有点的贡献都会 (-1),即 (ans+=(depth[v]-sz[v]+1))。那么我们把该值排个序,取最大的 (k) 个就行了。

反思:想到了点深度和子树大小,但没有把它们联系在一起考虑。

代码:

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int N=2e5+5;
vector<int>G[N];
int sz[N],a[N];
bool cmp(int x,int y)
{
    return x>y;
}
void dfs(int v,int p,int d)
{
    sz[v]=1;
    for(int i=0;i<G[v].size();i++)
    {
        int u=G[v][i];
        if(u==p)
            continue;
        dfs(u,v,d+1);
        sz[v]+=sz[u];
    }
    a[v]=d-sz[v];
}
int main()
{
    int n,k,v,u;
    ll ans=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        G[u].pb(v);
        G[v].pb(u);
    }
    dfs(1,1,1);
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=k;i++)
        ans+=a[i];
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/1024-xzx/p/12728912.html