洛谷P2680 运输计划

洛谷P2680 运输计划

题意:给一棵 n (n3×105) 个点的带权树, m (m3×105) 条路径。求某条边权值变为 0 后,所有路径长度的最大值,所有边这样搞的最小值。

做法:最小的最大,二分答案。二分最大值 x ,那么如果要满足所有路经长 x ,就等于存在某条边,使原来 >x 的路径都经过这条边,且 最大路径长 边长 x 。枚举所有边即可。问题在于如何判断边在路径上。

我们看一下这个的特点:询问次数少 (logn 次), 询问间修改量大 (n× 长为 n )。所以就是:差分!只不过是树上差分而已。对每条 x 的路径加 1 ,判断 sm[i]== 路径总数即可。

Tips:边差分一般不遍历边,而是 dfs 记录每个点与其父亲之间的边。从而遍历除根以外的点即可。

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
inline int read()
{
	int x = 0; char v = 0;
	while(!isdigit(v)) v = getchar();
	while(isdigit(v)) x = (x << 1) + (x << 3) + v - 48, v = getchar();
	return x;
}
int n, m;
int hd[N], nt[N << 1], to[N << 1], w[N << 1], tot, sm[N];
int fa[N][22], dep[N], dis[N], pre[N];
inline void add(int u, int v, int c)
{
	nt[++tot] = hd[u];
	hd[u] = tot;
	to[tot] = v;
	w[tot] = c;
}
inline void dfs(int u, int f)
{
	for(int i = 1; i <= 20; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1];
	int v;
	for(int e = hd[u]; e; e = nt[e])
		if((v = to[e]) ^ f)
		{
			dep[v] = dep[u] + 1;
		    fa[v][0] = u;
		    dis[v] = dis[u] + w[e];
		    pre[v] = e;///////////////////////////////////////
			dfs(v, u);
		}	
}
inline int LCA(int u, int v)
{
	int t;
	if(dep[u] < dep[v]) t = u, u = v, v = t;
	for(int i = 20; i >= 0; --i)
	    if(dep[fa[u][i]] >= dep[v]) 
			u = fa[u][i];
	if(u == v) return u;
	for(int i = 20; i >= 0; --i)
	    if(fa[u][i] ^ fa[v][i])
	        u = fa[u][i], v = fa[v][i];
	return fa[u][0];
}
inline void dfs2(int u)
{
	int v;
	for(int e = hd[u]; e; e = nt[e])
		if((v = to[e]) ^ fa[u][0])
		{
			dfs2(v);
			sm[u] += sm[v];
		}
}
struct node
{
	int s, t, d, lca;
	inline bool operator < (const node &A)const{return d > A.d;}
}fl[N];
inline bool check(int x)//////////////////////////////////////////
{
	for(int i = 1; i <= n; ++i) sm[i] = 0;
	int num = 0;
	for(int i = 1; i <= m; ++i)
	{
		if(fl[i].d <= x) {num = i - 1; break;}
		++num; 
		++sm[fl[i].s]; ++sm[fl[i].t];
		sm[fl[i].lca] -= 2;
	}
	dfs2(1);
	for(int i = 2; i <= n; ++i)
	    if(sm[i] == num && fl[1].d - w[pre[i]] <= x) return true;
	return false;
}
int main()
{
	n = read(); m = read();
	for(int i = 1, u, v, c; i < n; ++i)
	    u = read(), v = read(), c = read(), add(u, v, c), add(v, u, c);
	dfs(1, 0);
	for(int i = 1; i <= m; ++i)
	    fl[i].s = read(), fl[i].t = read(), fl[i].lca = LCA(fl[i].s, fl[i].t), 
		fl[i].d = dis[fl[i].s] + dis[fl[i].t] - (dis[fl[i].lca] << 1);
	sort(fl + 1, fl + m + 1);
	int L = 0, R = 3e8, mid;
	while(L < R)
	{
		mid = (L + R) >> 1;
		if(check(mid)) R = mid;
		else L = mid + 1;
	}
	cout << L;
	return 0;
}
posted @   Faker_yu  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示