2019ICPC上海H Tree Partition(二分)

求最大值最小,这种题目一般来说就是先猜一个二分

那我们发现,本题确实具有单调性,只要check出来能够小于等于k即可,因为这样一定能划分成k种

有人担心会不会二分的答案不能划分成k种,其实不可能,因为能划分成比k小的,就一定能划分成k种

之后就是dfs,用优先队列,如果一棵子树大了,就把他子树中的贪心从大往小划分

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+10;
int n,k;
int h[N],ne[N],e[N],w[N],idx;
ll sum[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a]++,h[a]=idx++;
}
int cnt;
bool dfs(int u,int fa,ll x){
    sum[u]=w[u];
    int i;
    priority_queue<ll> q;
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==fa)
            continue;
        if(!dfs(j,u,x))
            return false;
        sum[u]+=sum[j];
        q.push(sum[j]);
    }
    while(sum[u]>x){
        auto t=q.top();
        q.pop();
        cnt++;
        sum[u]-=t;
    }
    return cnt<=k-1;
}
bool check(ll x){
    return dfs(1,-1,x);
}
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    int cas=0;
    while(t--){
        cin>>n>>k;
        int i;

        for(i=1;i<=n;i++)
            h[i]=-1;
        for(i=1;i<n;i++){
            int a,b;
            cin>>a>>b;
            add(a,b);
            add(b,a);
        }
        for(i=1;i<=n;i++)
            cin>>w[i];
        ll l=0,r=1e14;
        for(i=1;i<=n;i++)
            l=max(l,1ll*w[i]);
        while(l<r){
            cnt=0;
            ll mid=l+r>>1;
            if(check(mid))
                r=mid;
            else
                l=mid+1;
        }
        cout<<"Case #"<<++cas<<": ";
        cout<<l<<endl;
    }
    return 0;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/14083990.html