E-DPRS 简解——2026牛客暑期多校训练营4

E-DPRS 简解

给定强连通带权有向图,\(n\)\(m\) 边,第 \(k\) 条边为 \((u_k,v_k,w_k)\)\(dis(i,j)\)\(i\)\(j\) 的最短路。图的值为 \(\max_{1\le i,j\le n, i\ne j} \frac{dis(i,j)}{dis(j,i)}\)\(q\) 次独立询问:给定边 \(k\) 和新权 \(x\)\(1\le x<w_k\)),临时将第 \(k\) 条边权改为 \(x\),求修改后图的值,之后恢复。

输入:\(T\) 组测试(\(1\le T\le 1000\))。每组 \(n,m,q\)\(2\le n\le m\le 2000\)\(1\le q\le 2000\)),\(\sum n,\sum m,\sum q\le 2000\)。接下来 \(m\)\(u_k,v_k,w_k\)\(1\le u_k,v_k\le n\)\(u_k\ne v_k\)\(1\le w_k\le 10^9\)),保证强连通。接下来 \(q\)\(k,x\)\(1\le k\le m\)\(1\le x<w_k\))。

输出:每个询问一行实数,绝对或相对误差不超过 \(10^{-6}\)

应该是出得非常好的一道最短路图论题,而且官方题解写得也非常生动易懂,这里仅仅是将此题放在博客上供个人复习,故写得较为简陋且与官解重复。

\(d(x,y)\) 为图中 \(x\)\(y\) 的最短路,最重要的结论是,图的价值就为

\[M=\max_{e=(u,v,w)}\frac{d(v,u)}{w} \]

由于 \(w\geq dis(u,v)\quad e=(u,v,w)\),于是 \(M\leq ans\)

\(ans\leq M\),证明如下(官方题解证明,有点巧妙):

任取两个不同的点 \(s, t\),考虑一条从 \(t\)\(s\) 的最短路
\(p_0 = t \to p_1 \to \cdots \to p_k = s\),其中第 \(i\) 条边的边权为 \(w_i\)
于是 \(d(t, s) = \sum_{i=1}^{k} w_i\)。从 \(s\) 返回 \(t\) 时,可以依次走每条边对应的反向最短路,因此

\[d(s, t) \leq \sum_{i=1}^{k} d(p_i, p_{i-1}) \leq \sum_{i=1}^{k} M w_i = M d(t, s). \]

所以 \(\frac{d(s,t)}{d(t,s)} \leq M\),结论得证。

综上 \(M=ans\)

于是在已知任意两点 \(u,v\) 最短距离的情况下,只需要所有枚举 \(m\) 条边即可计算答案。假设当前修改的边为 \(a\to b\) 的一条边权为 \(w\) 的边,修改后边权 \(x<w\),记新图中两点最短路为 \(d_x(u,v)\),则

\[d_x(u,v)=\min\{ d(u,v),d(u,a)+x+d(b,v)\} \]

此外注意枚举到 \((a,b,w)\) 这条边时,这条边的边权已经为 \(x\),分母改变了,具体实现见代码。

#include <bits/stdc++.h>

using namespace std;


typedef long long ll;
typedef pair<ll,ll>ttfa;
const int N=2003;
const ll INF=0x3f3f3f3f3f3f3f3f;

int n,m,ques;
int uu[N],vv[N];ll ww[N];
vector<ttfa>tar[N];

ll dis[N][N];bool vis[N];

int main(){
	int Test;scanf("%d",&Test);
	while(Test--){
		scanf("%d%d%d",&n,&m,&ques);
		for(int i=1;i<=n;++i)tar[i].clear();
		for(int i=1;i<=m;++i){
			scanf("%d%d%lld",&uu[i],&vv[i],&ww[i]);
			tar[uu[i]].push_back({vv[i],ww[i]});
		}
		priority_queue<ttfa,vector<ttfa>,greater<ttfa>>q;
		for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)dis[i][j]=INF;
		for(int x=1;x<=n;++x){
			for(int i=1;i<=n;++i)vis[i]=0;
			dis[x][x]=0;q.push({0,x});
			while(!q.empty()){
				int u=q.top().second;q.pop();
				if(vis[u])continue;
				vis[u]=1;
				for(auto [v,w]:tar[u]){
					if(dis[x][v]>dis[x][u]+w){
						dis[x][v]=dis[x][u]+w;
						q.push({dis[x][v],v});
					}
				}
			}
		}
		for(int T=1;T<=ques;++T){
			int id,a,b;ll x;scanf("%d%lld",&id,&x);
			double ans=0;
			a=uu[id],b=vv[id];
			for(int i=1;i<=m;++i){
				int u=uu[i],v=vv[i];
				ll w=(i==id?x:ww[i]);
				ans=max(ans,1.0*min(dis[v][u],dis[v][a]+x+dis[b][u])/w);
			}
			printf("%.10lf\n",ans);
		}
	}
	return 0;
}
posted @ 2026-09-20 18:12  BigSmall_En  阅读(5)  评论(0)    收藏  举报