Loading

【题解】[JOI2018] Commuter Pass

比较套路的题目。

首先我们需要求出 \(S\to T\) 的最短路可行边。

我们分别以 \(S/T\) 为起点,跑最短路得到 \(dist_1,dist_2\) ,如果两端 \(dist\) 之和加上边的长度为最短路,则当前边出现在一条最短路中。

现在从 \(U\to V\) ,免费的一定是一条连续的路径。

而这条免费的路径要么是顺着最短路径图走一段,要么是逆着最短路径图走一段,而不能同时有顺向或逆向走。

简单想了一个贪心,大概是先求出 \(U/V\) 到最短路径图的最近点 \(P,Q\),再从 \(P/Q\) 为起点出发顺向或逆向找到最近公共可达点,分别以 \(P,Q\) 为起点正图反图都跑一遍最短路。

码了 \(10\) 分钟感觉太麻烦了,不如直接分层图。第 \(1\) 层和第 \(4\) 层分别表示还未开始免费路径,已经结束免费路径。第 \(2\) 层表示免费路径顺着走,这一层就是最短路图,第 \(3\) 层表示免费路径逆着走,就是最短路图的反图。

最后再跑一遍最短路即可,一共跑三遍最短路,时间复杂度 \(\mathcal{O}((N+M)\log (N+M))\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 400005
#define int long long 
using namespace std;
int n,m,d[N],c[N],mk[N],h[N],tot,s,t,u,v;
struct edge{int to,nxt,val;}e[N];
void add(int x,int y,int z){e[++tot].nxt=h[x];h[x]=tot;e[tot].to=y;e[tot].val=z;}
typedef pair<int,int> Pr;
priority_queue<pair<int,int>>q;
vector<Pr>a[N];
void ins(int x,int y,int z){a[x].push_back(make_pair(y,z));}
void dij(){
	memset(d,0x3f,sizeof(d));
	d[s]=0;q.push(make_pair(0,s));
	while(!q.empty()){
		int x=q.top().second;q.pop();mk[x]=1;
		for(int i=h[x];i;i=e[i].nxt)if(d[x]+e[i].val<d[e[i].to])
			d[e[i].to]=d[x]+e[i].val,q.push(make_pair(-d[e[i].to],e[i].to));
		while(!q.empty()&&mk[q.top().second])q.pop();
	}
	memset(c,0x3f,sizeof(c));
	memset(mk,0,sizeof(mk));
	c[t]=0;q.push(make_pair(0,t));
	while(!q.empty()){
		int x=q.top().second;q.pop();mk[x]=1;
		for(int i=h[x];i;i=e[i].nxt)if(c[x]+e[i].val<c[e[i].to])
			c[e[i].to]=c[x]+e[i].val,q.push(make_pair(-c[e[i].to],e[i].to));
		while(!q.empty()&&mk[q.top().second])q.pop();
	}
	rep(x,1,n)
		for(int i=h[x];i;i=e[i].nxt)
			if(d[x]+e[i].val+c[e[i].to]==d[t]){
				ins(x+n,e[i].to+n,0),ins(e[i].to+n+n,x+n+n,0);
			}
}
void solve(){
	memset(d,0x3f,sizeof(d));
	memset(mk,0,sizeof(mk));
	d[u]=0;q.push(make_pair(0,u));
	while(!q.empty()){
		int x=q.top().second;q.pop();mk[x]=1;
		for(auto w:a[x]){
			int y = w.first,z = w.second;
			if(d[x] + z < d[y])d[y] = d[x] + z,q.push(make_pair(-d[y],y));
		}
		while(!q.empty()&&mk[q.top().second])q.pop();
	}
	printf("%lld\n",d[v+n+n+n]);
}
signed main(){
	scanf("%lld%lld",&n,&m);
	scanf("%lld%lld%lld%lld",&s,&t,&u,&v);
	rep(i,1,m){
		int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);
		add(x,y,z);add(y,x,z);
		ins(x,y,z);ins(y,x,z);
		ins(x+n+n+n,y+n+n+n,z);ins(y+n+n+n,x+n+n+n,z);
	}
	rep(i,1,n)ins(i,i+n,0),ins(i,i+n+n,0),ins(i+n,i+n+n+n,0),ins(i+n+n,i+n+n+n,0);
	dij();solve();
	return 0;
}
posted @ 2021-10-04 16:57  7KByte  阅读(50)  评论(0编辑  收藏  举报