題意:給一棵樹,現在要從上面劃出條互不相交的鏈(指邊不能共用),問這些鏈中長度最短的最長可以達到多少。
最短最長沒什麼好說的了,考慮二分。
考慮如何判定?
使用貪心。
給每個點都開一個,然後將子樹拼接後剩下的最長鏈插入這個點的裏面,然後從左往右檢索該,對於每個值二分出第一個值使得它們拼接後大於等於二分的值,然後拼接,最後把剩下的數裏面最大的往上傳即可。
#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;
}