求最大最小值或最小最大值十有八九是二分。
二分答案 + 树形贪心判断。
#include <cstdio>
#include <cstring>
#include <algorithm>
const int MAXN = 5e4 + 19;
struct Edge{
int to, next, dist;
}edge[MAXN << 1];
int cnt, head[MAXN];
inline void add(int from, int to, int dist){
edge[++cnt].to = to;
edge[cnt].dist = dist;
edge[cnt].next = head[from];
head[from] = cnt;
}
int q[MAXN], t;
int dp[MAXN];
bool vist[MAXN];
int dfs(int node, int val, int fa){
int res = 0; dp[node] = 0;
for(int i = head[node]; i; i = edge[i].next)
if(edge[i].to != fa)
res += dfs(edge[i].to, val, node);
t = 0;
for(int i = head[node]; i; i = edge[i].next)
if(edge[i].to != fa){
dp[edge[i].to] += edge[i].dist;
if(dp[edge[i].to] >= val)
++res;
else
q[++t] = dp[edge[i].to];
}
if(!t)
return res;
std::sort(q + 1, q + t + 1);
for(int i = 1; i <= t + 3; ++i)
vist[i] = false;
for(int i = 1; i < t; ++i)
if(!vist[i]){
int x = std::lower_bound(q + i + 1, q + t + 1, val - q[i]) - q;
if(x > t)
continue;
while(x <= t && vist[x])
++x;
if(x <= t){
vist[i] = true, vist[x] = true;
++res;
}
}
for(int i = t; i >= 1; --i)
if(!vist[i]){
dp[node] = q[i];
break;
}
return res;
}
int n, m;
int main(){
std::scanf("%d%d", &n, &m);
int l = 0x7fffffff, r = 0;
for(int u, v, w, i = 1; i < n; ++i){
std::scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
r += w;
if(w < l)
l = w;
}
r /= m;
while(l < r){
int mid = (l + r + 1) >> 1;
if(dfs(1, mid, 0) >= m)
l = mid;
else
r = mid - 1;
}
std::printf("%d\n", l);
return 0;
}