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;
}
posted @ 2025-09-11 20:14  WuMin4  阅读(11)  评论(0)    收藏  举报