题目:https://ac.nowcoder.com/acm/contest/560/I
题意:给你结点数为n的树,有n-1条边,每个结点都有一个权值,要你划分成k个连接的部分使每个部分的最小值最大
分析:对于这种最小值最大问题一般都是二分,二分答案,然后dfs如果一部分>=答案就把它截取下来,一直截完看它有没有k个部分。
Ac code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
ll a[maxn];
ll dp[maxn];
vector<int>edge[maxn];
int tot,k;
void dfs(int fa,int u,ll mid)
{
dp[u]=a[u];
for(int i=0;i<edge[u].size();i++)
{
int v=edge[u][i];
if(v!=fa){
dfs(u,v,mid);
dp[u]+=dp[v];
}
}
if(dp[u]>=mid){
dp[u]=0;
tot++;
}
}
bool check(ll mid)
{
tot=0;
dfs(0,1,mid);
return tot>=k;
}
int main()
{
int n,u,v;
scanf("%d%d",&n,&k);
for(int i=1;i<=n-1;i++){
scanf("%d%d",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
ll sum=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
sum+=a[i];
}
ll l=1,r=sum;
ll ans;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%lld\n",ans);
return 0;
}