洛谷 P2680 [NOIP2015 提高组] 运输计划

洛谷 P2680 [NOIP2015 提高组] 运输计划

题意

给出一棵树和 m 条路径,可以选择一条边,把边权改为 0,求 m 条路经长度最大值的最小值。

思路

看到最大值最小,可以想到二分答案,答案具有单调性。

考虑如何判定答案 x 是否可行。

统计所有长度大于 x 的路径,统计它们共同经过的边和长度的最大值。

如果把它们共同经过的一条边权改为 0 后,长度最大值缩小到 x 以下,则答案可行。

统计共同经过的边可以使用边权树上差分,统计每条边被经过的次数。

如果某条边被经过的次数等于长度大于 x 的路径数量,则它就被共同经过。

如果没有长度大于 x 的边,答案显然可行。

直接暴力二分 0 到极大值会时间超限。

求出最大边权 W 和所有路径长度最大值 M,二分区间为 [W,MW]

因为最多把最大边权设为 0W1000,可以通过。

时间复杂度:O((n+m)logW)

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 300005 + 5;
const int mod = 998244353;
int tot, ver[N << 1], nxt[N << 1], head[N], edge[N << 1];
int n, m, fa[N][20], de[N], dis[N], a[N];
struct path {int u, v, lca, w;};
path p[N];
void add(int x, int y, int z) {
	ver[++ tot] = y;
	nxt[tot] = head[x];
	head[x] = tot;
	edge[tot] = z;
}
void DFS(int x) {
    de[x] = de[fa[x][0]] + 1;
    for (int i = 1; i <= 19; i ++)
        fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for (int i = head[x], y; i; i = nxt[i]) {
        y = ver[i];
        if (y == fa[x][0]) continue;
        fa[y][0] = x, dis[y] = dis[x] + edge[i];
        DFS(y);
    }
}
inline int LCA(int x, int y) {
    if (de[x] < de[y]) swap(x, y);
    for (int i = 19; i >= 0; i --) 
        if (de[fa[x][i]] >= de[y]) x = fa[x][i];
    if (x == y) return x;
    for (int i = 19; i >= 0; i --)
        if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
    return fa[x][0];
}
void dfs(int x) {
	for (int i = head[x], y; i; i = nxt[i]) {
		if ((y = ver[i]) == fa[x][0]) continue;
		dfs(y);
		a[x] += a[y];
	}
}
bool check(int x) {
	memset(a, 0, sizeof(a));
	int cnt = 0, mx = 0;
	for (int i = 1; i <= m; i ++) {
		if (p[i].w > x) {
			a[p[i].u] ++;
			a[p[i].v] ++;
			a[p[i].lca] -= 2;
			cnt ++;
			mx = max(mx, p[i].w); 
		}
	}
	if (!cnt) return 1;
	dfs(1);
	for (int i = 2; i <= n; i ++) 
		if (a[i] >= cnt && mx - dis[i] + dis[fa[i][0]] <= x) return 1;
	return 0;
}
int main() {
	scanf("%d%d", &n, &m);
	int MAXW = 0;
	for (int i = 1, u, v, w; i < n; i ++) {
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w); add(v, u, w);
		MAXW = max(MAXW, w);
	}
	DFS(1);
	int maxw = 0; 
	for (int i = 1, u, v; i <= m; i ++) {
		cin >> u >> v;
		p[i] = {u, v, LCA(u, v), dis[u] + dis[v] - 2 * dis[LCA(u, v)]};
		maxw = max(maxw, p[i].w);
	}
	int l = maxw - MAXW, r = maxw, mid, res;
	while (l <= r) {
		mid = (l + r) >> 1;
		if (check(mid)) r = mid - 1, res = mid;
		else l = mid + 1;
	}
	printf("%d\n", res);
	return 0;
}  
posted @   maniubi  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示