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