洛谷 P5021 赛道修建

求最大最小值或最小最大值十有八九是二分。
二分答案 + 树形贪心判断。

#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;
}

猜你喜欢

转载自www.cnblogs.com/natsuka/p/12627509.html
今日推荐