CF2128F

CF2128F Strict Triangle & 模拟赛 T3

模拟赛中的题意:

给定一个图,和一个点 \(k\) ,每条边的边权有一个上界 \(r_i\) 和下界 \(l_i\)。求能否构造一组边权,使得图满足以下性质:

所有从 \(1\) 到 \(n\) 的最短路都不经过 \(k\) 。

\(n\le 5\times 10^5, m\le 10^6\) 。

显然的事情:一条边的边权只会取上界和下界。

第一步转换&简化题意:

这一步已经比较困难了。以下的所有路径都默认是从 \(1-n\) 的。

假设不经过 \(k\) 到达 \(n\) 的某条路径是 \(s\) ,我们要构造一个图使得不存在一个经过 \(k\) 的路径 \(t\) ,其长度比 \(s\) 短。

那么这两条路径一定是先分叉再汇合,所以 \(s\) 到达汇合点的时间必须早于 \(t\) 。

为了使得 \(t\) 到达汇合点的时间尽量晚, \(s\) 到达的时间尽量早。则可以将 \(s\) 路径上的边的边权全部取下界 \(l_i\),其余边取上界 \(r_i\)。

因此问题变成以下简化题面:

现在你是一个强盗,从 \(1\) 走到 \(n\),每走到一个城市,这里的居民就会立刻前往位于 \(k\) 的警察局报案,警察接到报案后会立刻

向各方向出动,只要和你重合就抓捕你。你走过一条边花费 \(l_i\) 时间,居民和警察花费 \(r_i\) 时间,问你能否逃脱抓捕。

下一步&关键矛盾:

在简化题意下,从 \(k\) 到其他点花的时间是固定的。为了不被抓捕,你希望警察已经出发的时间/距离尽量短。

所以对于每个点,我们如果求出 \(f_i\) 表示走到点 \(i\) 时警察已经出发的最大时间的最小值。

如果居民正在赶往警察局报警,还没有警察出发,则这个值为负, 表示警察将在这么多时间后出发。

然后可以类似 \(dij\) 的转移 \(f\) 。具体地:

设 \(dis_i\) 表示走上界从 \(k\) 到 \(i\) 的最短时间。

初始令 \(f_1=-dis_{1}\) 。其余为 \(INF\) 。

然后取出最小的 \(f_u\) ,令 \(f_v=min(f_v,max(f_u+l,-dis_v))\)

其中 \(l\) 表示下界。

如果有 \(f_n<dis_n\) 则可以构造出这样的图。

否则不行。

CODE:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+10,M=2e6+10;
const ll INF=1e18;
int T;
int n,m,k;
int head[N],to[M],nxt[M],lw[M],hh[M];
int cnt_edge=-1;
void add(int u,int v,int l,int r){
	++cnt_edge;
	nxt[cnt_edge]=head[u];
	head[u]=cnt_edge;
	to[cnt_edge]=v;
	lw[cnt_edge]=l;
	hh[cnt_edge]=r;
}
struct A{
	int x;ll d;
	bool operator < (const A &rhs) const{
		return d>rhs.d;
	}
};
priority_queue<A> pq,pq2;
ll dis[N];//k到其他点的距离 
bool vis[N];
void dij(){
	for (int i=1;i<=n;i++){
		dis[i]=INF;
		vis[i]=0;
	} 
	dis[k]=0;
	pq.push({k,0});
	while(!pq.empty()){
		int x=pq.top().x;ll d=pq.top().d;pq.pop();
		if (d>dis[x]) continue;
		vis[x]=1;
		for (int e=head[x];e!=-1;e=nxt[e]){
			int v=to[e],w=hh[e];
			if (vis[v]) continue;
			if (dis[x]+w<dis[v]){
				dis[v]=dis[x]+w;
				pq.push({v,dis[v]});
			}
		}
	}
}
ll f[N];
bool ins[N];
int main(){
	cin >> T;
	while(T--){
		cin >> n >> m >> k;
		memset(head,-1,sizeof head);
		for (int i=1,u,v,l,r;i<=m;i++){
			cin >> u >> v >> l >> r;
			add(u,v,l,r);
			add(v,u,l,r);
		}
		dij();
		for (int i=1;i<=n;i++){
			f[i]=INF;
			ins[i]=0;
		}
		pq2.push({1,-dis[1]});
		f[1]=-dis[1];
		while(!pq2.empty()){
			int x=pq2.top().x;ll d=pq2.top().d;pq2.pop();
			if (d<f[x]) continue;
			ins[x]=1;
			if (f[x]>=dis[x]) continue;
			for (int e=head[x];e!=-1;e=nxt[e]){
				int v=to[e],w=lw[e];
				if (ins[v]) continue;
				if (f[v]>max(f[x]+w,-dis[v])){
					f[v]=max(f[x]+w,-dis[v]);
					pq2.push({v,max(f[x]+w,-dis[v])});
				}
			}
		}
		if (f[n]<dis[n]) cout << "Yes" << endl;
		else cout << "No" << endl;
	}
	return 0;
}

posted @ 2026-10-28 21:21  wlhao  阅读(4)  评论(0)    收藏  举报