题意:给一棵树,现在要从上面划出mmm条互不相交的链(指边不能共用),问这些链中长度最短的最长可以达到多少。
最短最长没什么好说的了,考虑二分。
考虑如何判定?
使用贪心。
给每个点都开一个multisetmultisetmultiset,然后将子树拼接后剩下的最长链插入这个点的multisetmultisetmultiset里面,然后从左往右检索该multisetmultisetmultiset,对于每个值二分出第一个值使得它们拼接后大于等于二分的值,然后拼接,最后把剩下的数里面最大的往上传即可。
code:code:code:
#include <bits/stdc++.h>
using std::cin;
using std::cout;
#define regi register int
int n,m;
int head[500001],tot;
std::multiset<int>chain[100001];
std::multiset<int>::iterator left,right;
int Make;
struct edge{
int to;
int nxt;
int w;
}e[1000001];
inline void add(int x,int y,int z){
e[++tot]={y,head[x],z};
head[x]=tot;
}
int dfs(int x,int f,int Long){
chain[x].clear();
for(regi i=head[x];i;i=e[i].nxt){
regi y=e[i].to;
if(y==f)
continue;
regi tmp=dfs(y,x,Long)+e[i].w;
if(tmp>=Long){
++Make;
continue;
}
chain[x].insert(tmp);
}
int max=0;
for(left=chain[x].begin();left!=chain[x].end();++left){
right=chain[x].lower_bound(std::max(Long-*left,*left+1));
if(right!=chain[x].end()&&*left+*right>=Long){
chain[x].erase(right);
++Make;
}
else
if(left!=--chain[x].end()&&*left*2>=Long){
chain[x].erase(++left);
++Make;
}
else
max=std::max(max,*left);
}
return max;
}
inline bool check(int x){
Make=0;
dfs(1,0,x);
if(Make>=m)
return 1;
return 0;
}
main(){
std::ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(regi i=1,x,y,z;i<n;++i){
cin>>x>>y>>z;
add(x,y,z);
add(y,x,z);
}
int l=1,r=0x3f3f3f3f;
while(l<r){
regi mid=l+r+1>>1;
if(check(mid))
l=mid;
else
r=mid-1;
}
cout<<l;
return 0;
}