suxxsfe

一言(ヒトコト)

P2865 Roadblocks(严格次短路)

https://www.luogu.com.cn/problem/P2865
https://loj.ac/problem/10076

\(1\)\(n\) 的严格次短路

考虑使用 dij
记录两个数组,dis[u],dis2[u] 分别表示 \(1\)\(u\) 的最短路,严格次短路
更新时,取出堆顶的节点 \(u\),设它在堆种的距离大小是 \(now\_dis\)(不是那两个数组里的值),遍历所以和它相邻的节点 \(v\)

  • \(dis_v>now_dis+W_i\),那就先 \(dis2_v=dis_v\),就是当前的最短路变成了严格次短路,然后再中 \(v\) 更新 \(u\),最后把 \(dis_v,dis2_v\) 都放入堆里
  • 对于其它情况,如果 \(dis2_v>now_dis+W_i\),且 \(now_dis+W_i>dis_v\),就只更新 \(diw2_v\) 并放入堆中,后一个条件是为了保证长度是严格次短

然后就不像一般的 dij 每个点只更新一次了

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
#define N 5005
#define M 200005
struct graph{
	int fir[N],nex[M],to[M],w[M],tot;
	inline void add(int u,int v,int z){
		to[++tot]=v;w[tot]=z;
		nex[tot]=fir[u];fir[u]=tot;
	}
}G;
int n,m;
struct data{
	int i,dis;
}heap[N*20];
int size;
int dis[N],dis2[N];
inline void push(data x){
	heap[++size]=x;
	reg int i=size,fa;
	while(i>1){
		fa=i>>1;
		if(heap[fa].dis<=heap[i].dis) return;
		std::swap(heap[fa],heap[i]);i=fa;
	}
}
inline data pop(){
	data ret=heap[1];heap[1]=heap[size--];
	reg int i=1,ls,rs;
	while((i<<1)<=size){
		ls=i<<1;rs=ls|1;
		if(rs<=size&&heap[rs].dis<heap[ls].dis) ls=rs;
		if(heap[i].dis<=heap[ls].dis) break;
		std::swap(heap[ls],heap[i]);i=ls;
	}
	return ret;
}
inline void dij(){
	push((data){1,0});
	dis[1]=0;
	reg int u,v,nowdis;
	data tmp;
	while(size){
		tmp=pop();u=tmp.i;nowdis=tmp.dis;
		for(reg int i=G.fir[u];i;i=G.nex[i]){
			v=G.to[i];
			if(dis[v]>nowdis+G.w[i]){
				dis2[v]=dis[v];
				dis[v]=nowdis+G.w[i];
				push((data){v,dis[v]});
				push((data){v,dis2[v]});
			}
			else if(dis2[v]>nowdis+G.w[i]&&nowdis+G.w[i]>dis[v]){
				dis2[v]=nowdis+G.w[i];
				push((data){v,dis2[v]});
			}
		}
	}
}
int main(){
	n=read();m=read();
	for(reg int x,y,z,i=1;i<=m;i++){
		x=read();y=read();z=read();
		G.add(x,y,z);G.add(y,x,z);
	}
	std::memset(dis,0x3f,sizeof dis);std::memset(dis2,0x3f,sizeof dis2);
	dij();
	printf("%d",dis2[n]);
	return 0;
}
posted @ 2020-07-24 14:33  suxxsfe  阅读(147)  评论(0编辑  收藏  举报