2019 ICPC Asia Shanghai - Tree Partition

题目链接:2019 ICPC Asia Shanghai - Tree Partition


首先权值最大的块,最小。我们可以想到二分。

然后看是否能够满足。我们对于每个点,假设子树都是小于当前二分的值mid,对于当前点,如果把全部子树加上都是合法的,那么肯定直接加上即可。

如果全部加上不合法,肯定就需要丢弃一些子树。肯定贪心丢掉最大的子树,直到合法。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int n,k,a[N],flag,cnt,sum[N];
vector<int> g[N];
inline void add(int a,int b){g[a].push_back(b),g[b].push_back(a);}
inline void init(){
	for(int i=1;i<=n;i++)	g[i].clear(),sum[i]=0;
}
void dfs(int x,int fa,int mid){
	sum[x]=a[x];
	if(sum[x]>mid||flag){flag=1;	return ;}
	for(auto to:g[x]){
		if(to==fa)	continue;
		dfs(to,x,mid);	sum[x]+=sum[to];
	}
	if(sum[x]>mid){
		vector<int> v;
		for(auto to:g[x])	if(to!=fa)	v.push_back(sum[to]);
		sort(v.begin(),v.end());
		while(sum[x]>mid){
			cnt++;	sum[x]-=v.back(); v.pop_back();
		}
	}
	if(cnt>k-1)	flag=1;
}
inline int check(int mid){
	flag=cnt=0;	dfs(1,1,mid);
	return !flag;
}
inline int solve(){
	cin>>n>>k;	init();
	for(int i=1,a,b;i<n;i++)	scanf("%lld %lld",&a,&b),add(a,b);
	for(int i=1;i<=n;i++)	scanf("%lld",&a[i]);
	int l=0,r=1e14;
	while(l<r){
		int mid=l+r>>1LL;
		if(check(mid))	r=mid;
		else	l=mid+1;
	}
	return l;
}
signed main(){
	int T;	cin>>T;
	for(int i=1;i<=T;i++)	printf("Case #%lld: %lld\n",i,solve());
	return 0;
}
发布了604 篇原创文章 · 获赞 242 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/104345133
今日推荐