# 洛谷P5021 赛道修建

#include <bits/stdc++.h>
#define N 1000101
using namespace std;
struct edg {
int to, nex, len;
}e[N];
int n, m, cnt, root = 1, ha, lin[N], dp[N], temp[N], vis[N], tot;//dp[i]表示i的点权
inline void add(int f, int t, int l)
{
e[++cnt].len = l;
e[cnt].to = t;
e[cnt].nex = lin[f];
lin[f] = cnt;
}
void dfs(int now, int fa, int len)
{

int tot = 0;
for (int i = lin[now]; i; i = e[i].nex)
{
int to = e[i].to;
if (to != fa)
dfs(to, now, len);
}
for (int i = lin[now]; i; i = e[i].nex)
{
int to = e[i].to;
if (to != fa)
temp[++tot] = dp[to] + e[i].len;
}

sort(temp + 1, temp + 1 + tot); //将当前i到结尾的所有链处理出来。
//	oprintf("%d %d\n", now, temp[tot]);
for (int i = tot; i >= 1 && temp[i] >= len; i--)
tot--, ha--;
for (int i = 1; i <= tot; i++)
{
if (vis[i] == now)
continue;//vis判断是否链经过now
int a = len - temp[i];//开始二分
int l = i + 1, r = tot, mid, ans = tot + 1;
while (l <= r)
{
mid = (l + r) >> 1;
if (temp[mid] >= a)//如果当前的另一条链比a大的话，说明此时可以用来求解
{
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
while (vis[ans] == now && ans <= tot)
ans++;
if (ans <= tot)
{
ha--, vis[i] = vis[ans] = now;
}
}
dp[now] = 0;
for (int i = tot; i >= 1; i--)//找到第一个最长的链，然后
if (vis[i] != now)
{
dp[now] = temp[i];
break;
}
//	printf("%d\n", dp[now]);
}
bool check(int mid)//判断mid，对于每条路径取到就停止，最后判断是否超过m个比mid大的路径
{
ha = m;       // now是当前能满足多少个路径。
memset(vis, 0, sizeof(vis));
dfs(root, 0, mid);
return ha <= 0;
}
int main()
{
scanf("%d%d", &n, &m);
int l = 0, r = 0;
for (int i = 1; i < n; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
r += c;
}
int mid, ans;
while (l <= r)
{
mid = (l + r) >> 1;
if (check(mid))
{
ans = mid;
l = mid + 1;
}
else
r = mid - 1;
}
printf("%d", ans);
return 0;
}


posted @ 2019-11-09 18:50  刘文尧  阅读(105)  评论(0编辑  收藏