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; }
没有人不辛苦,只有人不喊疼