qoj1828 TraveLog
题意
给出一个有向带权图。
有一条 \(1\to n\) 的最短路。给出 \(1\) 到这条最短路上某些点的最短路长度,询问这条最短路是否无解,唯一解,多解,并输出唯一解的方案。
\(n\le 2\times 10^5,m\le 3\times 10^5\)。
思路
首先跑一遍 dij 求出 \(1\to i\) 的最短路长度,记为 \(d_i\)。
对于一条边 \((u,v,w)\),如果 \(d_u+w\neq d_v\),则说明这条边不是某条最短路的边。
剩下的边即为所有可能在最短路上的边。
接着对于一条最短路上的边 \((u,v,w)\),如果对于给出的某个最短路长度 \(l\) 有 \(d_u<l<d_v\),则这条边也不可能是最短路上的边,因为在 \(u\) 前面的点 \(u'\) 都有 \(d_{u'}<l\),\(v\) 后面的点都有 \(d_{v'}>l\),即不存在一个点 \(x\) 满足 \(d_x=l\)。\(l\) 显然可以二分查找。注意当 \(l>d_n\) 时显然无解。
最后满足以上条件的所有边即为最短路上可能的边,直接判断即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
struct node{
int x,d;
};
struct node2{
int x,y,d;
}b[300005];
bool operator<(node x,node y){
return x.d>y.d;
}
int n,m,d,dis[200005];
bool vis[200005],ok;
vector<node> t[200005];
vector<int> p,t2[200005],ans;
void dij(){
memset(dis,0x3f,sizeof(dis));
priority_queue<node> q;
q.push({1,0});
dis[1]=0;
while(!q.empty()){
node u=q.top();q.pop();
if(vis[u.x]) continue;
vis[u.x]=true;
for(node v:t[u.x]){
if(dis[v.x]>=dis[u.x]+v.d){
dis[v.x]=dis[u.x]+v.d;
q.push({v.x,dis[v.x]});
}
}
}
}
void dfs(int x){
vis[x]=true;
if(!ok)
ans.push_back(x);
if(x==n){
ok=1;
return;
}
for(int v:t2[x])
if(!vis[v]) dfs(v);
else{
cout<<1;
exit(0);
}
if(!ok)
ans.pop_back();
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>m>>d;
for(int x,y,v,i=1;i<=m;i++){
cin>>x>>y>>v;
b[i]={x,y,v};
t[x].push_back({y,v});
}
for(int x,i=1;i<=d;i++)
cin>>x,p.push_back(x);
sort(p.begin(),p.end());
dij();
if(*--p.end()>dis[n]){
cout<<0;
return 0;
}
p.push_back(1e18);
for(int i=1;i<=m;i++){
node2 v=b[i];
if(dis[v.x]+v.d==dis[v.y]){
int r=*upper_bound(p.begin(),p.end(),dis[v.x]);
if(r>=dis[v.y])
t2[v.x].push_back(v.y);
}
}
memset(vis,0,sizeof(vis));
dfs(1);
if(ok){
cout<<ans.size()<<endl;
for(int v:ans) cout<<v<<endl;
return 0;
}
else
cout<<0;
return 0;
}

浙公网安备 33010602011771号