The 2019 ICPC Asia Shanghai Regional Contest · H Tree Partition · 二分
程序员文章站
2022-06-02 20:01:39
...
题解
题意:将一棵树切k-1刀分成k棵树,问这k棵树里最大的权值是多少
代码参考此博客
- 寻找答案的上界
二分 - 如何判断满足条件?
从下往上搜寻每棵树的权值,如果当前树的权值大于给定的上界x,进行切割,从最大的子树切割,使得剩余的子树的权值尽量的小,用最少的切割次数满足条件
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int n,m,k;
struct egde{
int to,next;
}e[N];
int head[N],tot;
void add(int u,int v){
e[++tot]={v,head[u]};
head[u]=tot;
}
ll w[N],sum[N];
bool flag;//判断状态是否合法
int cnt;//统计切割个数
void dfs(int u,int fa,ll x){//当前节点 父节点 设定的最大子树的权值
sum[u]=w[u];
if(sum[u]>x || flag==0){//如果单点都不符合 or 已经不符合了
flag=0;
return ;
}
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v!=fa){
dfs(v,u,x);
sum[u]+=sum[v];//把所有儿子加上
}
}
if(!flag)return ;
if(sum[u]>x){
vector<ll>ve;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v!=fa)
ve.push_back(sum[v]);
}
sort(ve.begin(),ve.end());
while(sum[u]>x){
cnt++;
sum[u]-=ve.back();//切割子树 每次取最大
ve.pop_back();
}
}
if(cnt>k-1){
flag=0;
return ;
}
}
bool legal(ll x){
flag=true,cnt=0;
dfs(1,0,x);
if(flag) return true;
else return false;
}
int main(){
ios::sync_with_stdio(0);
int T;
cin>>T;
for (int cs = 1; cs <= T; ++cs) {
cin>>n>>k;
//init
tot=0;
fill(head,head+1+n,0);
fill(sum,sum+1+n,0);
for (int i = 1,u,v; i <= n-1; ++i) {
cin>>u>>v;
add(u,v);
add(v,u);
}
for (int i = 1; i <= n; ++i) {
cin>>w[i];
}
ll l=0,r=1e14+1;
while(l<r){
ll mid=l+r>>1;
if(legal(mid)){
r=mid;
}else l=mid+1;
}
printf("Case #%d: %lld\n",cs,r);
}
return 0;
}
上一篇: Mac OS 10.15 修改登录壁纸
下一篇: Spring Data Redis介绍