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

浙公网安备 33010602011771号