codeforce 1337C. Linova and Kingdom

许愿单抽出呆鹅

一共有N个城市,城市之间组成了一个树,选择K个当industry city,剩下tourism city,每个industry city要派一个使者去根节点,这个使者的happiness等于其到根节点之间最短路上的tourism的数量,求使者总happiness的最大值


这个题我们可以计算如果某一结点当industry city对总happiness的贡献度。
首先记dep[i]为结点i的深度,sizu[i]为以i结点为根的子树的结点个数
其次,引入引理:如果结点u为tourism city,那么其父节点一定同样为tourism city
对于叶节点,其贡献值显然为 dep[i] - 1
如果非叶结点,那么先减去其为tourism city时贡献sizu[i] - 1,再加上为industry city时的贡献dep[i] - 1,故总贡献为 dep[i] - sizu[i]
最后sort取前最大的k个相加即可

#pragma GCC diagnostic error "-std=c++11"
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return

#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
const int maxn = 2e5+5;

template<class T> void _deb(const char *name,T val){
    cout<<name<<val<<endl;
}

int N,k;
vector<int> adj[maxn];
bool vis[maxn];
int val[maxn];
int dfs(int node,int depth);
inline bool cmp(int a,int b){
    re a>b;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin>>N>>k;
    rep(i,0,N-1){
        int a,b;
        cin>>a>>b;
        adj[a].Push(b);
        adj[b].Push(a);
    }

    dfs(1,1);

    sort(val+1,val+N+1,cmp);
    ll ans = 0;
    rep(i,1,k+1)
        ans += (ll)val[i];
    cout<<ans<<endl;

    return 0;
}

int dfs(int node,int depth){
    int sum = 1;
    vis[node] = true;
    bool connected = false;
    rep(i,0,getLen(adj,node)){
        int &to = adj[node][i];
        if(!vis[to]){
            connected = true;
            sum+=dfs(to,depth+1);
        }
    }
    if(!connected)
        val[node] = depth - 1;
    else
        val[node] = depth - sum;
    re sum;
}

猜你喜欢

转载自blog.csdn.net/white_156/article/details/105695658
今日推荐