2019 Shanghai ICPC H.Tree Partition

Question : Given a tree, each point has its own weight, let you divide the tree into k trees, and find the minimum and maximum value of the sum of the node weights of each tree.
Idea : Minimize the maximum value. It is easy to think of a binary answer.
Then we consider how to check. Dividing into k trees is equivalent to cutting k-1 knives. We perform dfs. For the sum of all the nodes of a tree, if the sum of the node weights of this subtree is greater than the two-point answer mid, we cut a knife. In order to ensure that the number of cuts is as few as possible, we use one The big top stacks the sum of the weights of each subtree, and gives priority to cutting down the larger ones.
If the number of cuts is less than or equal to k, then the answer can be smaller, that is, r=mid
otherwise l=mid

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+50;
typedef long long ll;
vector<int> e[N];
ll va[N],w[N];
struct node{
    
    
    int v;
    friend bool operator<(node a,node b){
    
    
        return va[a.v]<va[b.v];
    };
};
ll mid;
int cnt;
void dfs(int x,int f){
    
    
    priority_queue<node> que;
    for(auto &y:e[x]){
    
    
        if(f==y) continue;
        dfs(y,x);
        va[x]+=va[y];
        que.push({
    
    y});
    }
    while(va[x]>mid && !que.empty()){
    
    
        va[x]-=va[que.top().v];
        que.pop();
        ++cnt;
    }
}
int main(){
    
    
    int T;cin>>T;
    int ca=0;
    while(T--){
    
    
        int n,k;cin>>n>>k;
        --k;
        for(int i=1;i<=n;i++) e[i].clear();
        for(int i=1;i<n;i++){
    
    
            int u,v;cin>>u>>v;
            e[v].push_back(u);
            e[u].push_back(v);
        }
        ll l=0;
        for(int i=1;i<=n;i++){
    
    
            cin>>w[i];
            l=max(l,1ll*w[i]);
        }
        --l;
        ll r=1e14+1;
        while(l+1<r){
    
    
            mid=l+r>>1;
            for(int i=1;i<=n;i++) va[i]=w[i];
            cnt=0;
            dfs(1,0);
            if(cnt<=k) r=mid;
            else l=mid;
        }
        printf("Case #%d: %lld\n",++ca,r);
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_43563669/article/details/111696574