P3831 [SHOI2012]回家的路

分层图基础题,就是建图稍有麻烦

P3831 [SHOI2012]回家的路-LMLPHP


 

#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;
}
//P3831 [SHOI2012]回家的路 https://www.luogu.com.cn/problem/P3831
//一个网格,只能沿一个方向(横或纵)走
//某些交叉点可以改变方向
//沿一个方向走的时候,走一格花费两个时间,改变一次方向花费一个时间
//给出这些点,问网格中两点之间最短时间 //分层图,为每个可以改变方向的点(按照题目背景是换乘点),分别创建两个虚拟节点
//一个是横着走的,也就是走到这里只能继续横着走
//一个是纵列方向走
//然后,对于每一横行,依次从左往右把这些在一行的点连边
//纵列也是如此
//然后每一个换乘点,横纵方向的两个点之间连一个时间为 1 的点,表示换成 //起点和终点也看作换乘点,这样方便我们连边
//只不过它们的横纵方向的两点间边权为 0 ,因为在起点并不存在换乘的问题 //1-m 是横列换乘点的编号
//m+1 是起点的横列
//m+2 是终点的横列
//m+3-2*m+2 是纵列换乘点的编号
//2*m+3 起点纵列
//2*m+4 终点纵列
//1-m 分别和 m+2-2*m+2 连权值为 1 的边
//m+1 和 2*m+3 以及 m+2 和 2*m+4 连权值为 0 的边
//以 m+1 或 2*m+3 任意一个为虚构的图中的起点
//以 m+2 或 2*m+4 任意一个为虚构的图中的终点
//设横列编号为 id 则对应的纵列编号为 id+m+2 //数组尽量开大,一开始算错 WA 了
struct data{
int x,y,id;
}a[100009];
int dis[200009],in[200009];
int fir[200009],nex[700006],to[700006],w[700006],tot;
int heap[200009],size;
inline int cmpx(data aa,data aaa){return aa.x==aaa.x?aa.y<aaa.y:aa.x<aaa.x;}
inline int cmpy(data aa,data aaa){return aa.y==aaa.y?aa.x<aaa.x:aa.y<aaa.y;}
inline void add(int u,int v,int len){
to[++tot]=v;w[tot]=len;
nex[tot]=fir[u];fir[u]=tot;
}
inline void link(int u,int v,int len){
add(u,v,len);add(v,u,len);
}
inline void push(int x){
heap[++size]=x;
reg int i=size,fa;
while(i>1){
fa=i>>1;
if(dis[heap[fa]]<=dis[heap[i]]) return;
std::swap(heap[fa],heap[i]);i=fa;
}
}
inline int pop(){
int ret=heap[1];heap[1]=heap[size--];
int i=1,ls,rs;
while((i<<1)<=size){
ls=i<<1;rs=ls|1;
if(rs<=size&&dis[heap[rs]]<dis[heap[ls]]) ls=rs;
if(dis[heap[ls]]>=dis[heap[i]]) break;
std::swap(heap[i],heap[ls]);i=ls;
}
return ret;
}
inline void dij(int start){
std::memset(dis,0x3f,sizeof dis);dis[start]=0;
push(start);in[start]=1;
while(size){
reg int u=pop(),v;in[u]=0;
for(reg int i=fir[u];i;i=nex[i]){
v=to[i];
if(dis[v]>dis[u]+w[i]){
dis[v]=dis[u]+w[i];
if(!in[v]) push(v),in[v]=1;
}
}
}
}
inline void build(int m){
std::sort(a+1,a+1+m+2,cmpx);
for(reg int i=1;i<=m+2;){
int now_x=a[i].x;
for(i++;i<=m+2&&a[i].x==now_x;i++) link(a[i].id,a[i-1].id,(a[i].y-a[i-1].y)<<1);
}
std::sort(a+1,a+1+m+2,cmpy);
for(reg int i=1;i<=m+2;){
int now_y=a[i].y;
for(i++;i<=m+2&&a[i].y==now_y;i++) link(a[i].id+m+2,a[i-1].id+m+2,(a[i].x-a[i-1].x)<<1);
}
for(reg int i=1;i<=m;i++) link(i,i+m+2,1);
link(m+1,2*m+3,0);link(m+2,2*m+4,0);
}
int main(){
read();int m=read();
for(reg int i=1;i<=m+2;i++) a[i].x=read(),a[i].y=read(),a[i].id=i;
build(m);
dij(m+1);
std::printf("%d",dis[2*m+4]==0x3f3f3f3f?-1:dis[2*m+4]);
// EN;EN;
// for(reg int i=1;i<=m*2+4;i++){
// std::printf("%d : ",i);
// for(reg int j=fir[i];j;j=nex[j]) std::printf("%d ",to[j]);
// EN;
// }
return 0;
}
05-28 23:18