部分分:m=1 直径,菊花图 对边权排序,每次取最大最小合并,链 dp覆盖啥的
二叉树的话,二分答案,每个儿子要么和x连在一起往上传,要么和另外一个儿子合并(长度和大于mid),(统计以点x为lca的),x取大的儿子的f值,因为
正解把菊花图和二叉树合在一起,对每个点的儿子不断取两个边权加起来刚好大于mid的,然后剩下的取一个最大的传给父亲,用set实现
说起来容易做起来难....
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=50009;
int n,m,ans;
struct node{
int v,nxt,w;
}e[maxn<<1];
int head[maxn],cnt;
inline void add(int u,int v,int w){
e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
multiset<int>s[maxn];
ll dfs(int x,int fa,int k){
s[x].clear();
int val;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].v;if(y==fa)continue;
val=dfs(y,x,k)+e[i].w;
if(val>=k)ans++;
else s[x].insert(val);
}
int mx=0;
while(!s[x].empty()){
if(s[x].size()==1)return max(mx,*s[x].begin());
multiset<int>::iterator it=s[x].lower_bound(k-*s[x].begin());//找到一个可以和当前加起来>=lmt的最小元素
if(it==s[x].begin()&&s[x].count(*it)==1)it++;
if(it==s[x].end()){//没找到取max上传
mx=max(mx,*s[x].begin());
s[x].erase(s[x].find(*s[x].begin()));
}
else{//合并,删掉元素
ans++;
s[x].erase(s[x].find(*it));
s[x].erase(s[x].find(*s[x].begin()));
}
}
return mx;
}
bool check(ll md){
ans=0;
dfs(1,0,md);
if(ans>=m)return 1;
return 0;
}
int main(){
scanf("%d%d",&n,&m);ll r=1;
for(int i=1,u,v,w;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);add(v,u,w);r+=w;
}
ll l=0;r/=(ll)m;r+=1;
while(l<r){
ll mid=l+r>>1;
if(check(mid))l=mid+1;
else r=mid;
}
printf("%lld",r-1);
}