P3831 [SHOI2012]回家的路
分层图基础题,就是建图稍有麻烦

#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;
}
P3831 [SHOI2012]回家的路的更多相关文章
- 题解 P3831 [SHOI2012]回家的路
什么叫分层图最短路,我不会/kk 感觉自己做法和其他题解不大一样所以过来发篇题解了. 未刻意卡常拿下最优解 题目大意 就是说给你一个 \(n \times n\) 的网格图和 \(m\) 个可换乘点, ...
- [SHOI2012]回家的路
题目背景 SHOI2012 D2T1 题目描述 2046 年 OI 城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由2n2n条地铁线路构成,组成了一个nn纵nn横的交通网.如 ...
- [SHOI2012]回家的路 最短路
---题面--- 题解: 吐槽:找了好久的错,换了n种方法,重构一次代码,,,, 最后发现,,, 数组开小了,其实一开始尝试开大了数组,但唯独没有尝试开大手写队列的数组.... 思路: 有两种方法,这 ...
- Bzoj 2834: 回家的路 dijkstra,堆优化,分层图,最短路
2834: 回家的路 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 62 Solved: 38[Submit][Status][Discuss] D ...
- 分层图最短路【bzoj2834】: 回家的路
分层图最短路[bzoj2834]: 回家的路 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2834 这道题难在建边. 自己写的时候想到了 ...
- bzoj 2834: 回家的路
题目 F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ ModifyUser DCOI Logout 捐赠本站 Notice:1 ...
- 洛谷P3831 回家的路
题目背景 SHOI2012 D2T1 题目描述 \(2046\) 年 \(OI\) 城的城市轨道交通建设终于全部竣工,由于前期规划周密,建成后的轨道交通网络由\(2n\)条地铁线路构成,组成了一个\( ...
- BZOJ.2834.回家的路(最短路Dijkstra 拆点)
题目链接 对于相邻的.处在同在一行或一列的车站连边,然后用dis[x][0/1](或者拆点)分别表示之前是从横边还是竖边到x的,跑最短路. 我选择拆点.. //13028kb 604ms #inclu ...
- 解题:SHOI 2012 回家的路
题面 完了,做的时候已经想不起来分层图这个东西了QAQ 对于这种“多种”路径加中转站的题,还有那种有若干次“特殊能力”的题,都可以考虑用分层图来做 显然只需要记录所有的中转站+起点终点,然后拆出横竖两 ...
随机推荐
- String 对象-->substr() 方法
1.定义和用法 substr() 方法可在字符串中抽取从 开始 下标开始的指定数目的字符. 语法: string.substr(start,length) 参数: start:提取开始下标 lengt ...
- 配置spark历史服务(spark二)
1. 编辑spark-defaults.conf位置文件 添加spark.eventLog.enabled和spark.eventLog.dir的配置修改spark.eventLog.dir为我们之前 ...
- 【java 数据结构】还不会二叉树?一篇搞定二叉树
二叉树是我们常见的数据结构之一,在学习二叉树之前我们需要知道什么是树,什么是二叉树,本篇主要讲述了二叉树,以及二叉树的遍历. 你能get到的知识点? 1.树的介绍 2.二叉树的介绍 3.二叉树遍历的四 ...
- flex实现三列布局
css3新引入的flex在某些情况下布局非常实用 因为它是弹性盒子所以自适应效果会很棒 不过各项布局方案还是各有优劣 <!DOCTYPE html> <html lang=" ...
- 006-循环结构(下)-C语言笔记
006-循环结构(下)-C语言笔记 学习目标 1.[掌握]do-while循环结构 2.[掌握]for循环结构 3.[掌握]嵌套循环 一.do-while循环结构 do-while语法: 1 2 ...
- AQS系列(七)- 终篇:AQS总结
前言 本文是对之前AQS系列文章的一个小结,首先看看以下几个问题: 1.ReentrantLock和ReentrantReadWriteLock的可重入特性是如何实现的? 2.哪个变量控制着锁是否被占 ...
- Salesforce 学习 | 官方总结最实用的Spring '20新功能
在Spring '20正式发布之前,Trailblazers 社区举行了一个名为Treasure Hunt的在线活动,通过预览沙盒,分享他们认为Spring ‘20中最重要的功能.这篇文章就来盘点一下 ...
- 2007 NOIP T1奖学金
奖学金(07NOIPT1): [题目描述] 某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金.期末,每个学生都有3门课的成绩:语文.数学.英语.先按总分从高到低排序,如果 ...
- @SessionAttributes 的使用
@SessionAttributes 注解只用作用在 类 上,作用是将指定的 Model 的键值对保存在 session 中.可以让其他请求共用 session 中的键值对. 指定保存的属性名 作用是 ...
- css 样式中 margin padding和top类定位的区别
1 margin margin 是外边距的意思,是边框到外部另一元素之间的距离,允许使用负值 语法结构: margin:5px auto; 意思上下为5,左右平均居中 ...