我们是想跑最短路的

我们有两种建图方式:

1.对于每个doge i,连向B[j]==B[i]+P[i]*k ,k=..,-2,-1,0,1,2,... ,边权=|k|,这样连的复杂度是$O(N\sum\limits_{i=1}^{m}\frac{1}{P[i]})$

2.对于每个楼i,建max(P[i])个点,表示可以有一个doge经过这个楼来跳j个距离,也就是说,给P[i][j]连向P[i-j][j]和P[i+j][j],边权=1,而且还要给所有的P[i]连起来,边权是0.

这样连的复杂度是$O(N\sum\limits_{i=1}^{m}P[i])$,其中P[i]是互不相同的(相同就不加了)

然而都过不了

然后我们发现,复杂度一个是乘P[i],一个是除以P[i],这就启发我们采用分块的思想,对于P[i]大于$\sqrt{N}$的使用第1种建法,小于的使用第二种建法,整体的复杂度就变成$O(N\sqrt{N})$了

然而因为玄学的常数问题,我们需要:

1.让那个分块的边界取$min(\sqrt{N},100)$(我也不知道为什么)

2.在做最短路的时候再计算边,而不是提前都建好

3.深吸一口氧气(必要)

4.使用spfa而不是dijkstra(我也不知道为什么,但我还是用了dijkstra,然后就挂了...)

(代码写一年还写得巨丑)

 #include<bits/stdc++.h>
#define pa pair<int,int>
#define lowb(x) ((x)&(-(x)))
#define REP(i,n0,n) for(i=n0;i<=n;i++)
#define PER(i,n0,n) for(i=n;i>=n0;i--)
#define MAX(a,b) ((a>b)?a:b)
#define MIN(a,b) ((a<b)?a:b)
#define CLR(a,x) memset(a,x,sizeof(a))
#define rei register int
using namespace std;
typedef long long ll;
const int maxn=,sqrtn=; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} struct Node{
int x,y,d;bool isp;
Node (int a,int b,int c,bool s){x=a,y=b,d=c,isp=s;}
}S=Node(,,,);
int N,SN,M,B[maxn],P[maxn];
int dis[maxn*sqrtn],poi[maxn][],ph[maxn];
bool flag[maxn*sqrtn];
priority_queue<Node,vector<Node>,greater<Node> > q; bool operator > (Node a,Node b){return a.d>b.d;}
inline int id(Node a){return a.isp?a.x:M++a.x+a.y*N;}
inline void print(int x,Node a){printf("Node%d:%d %d %d %d\n",x,a.x,a.y,a.d,a.isp);} inline int dijkstra(){
memset(dis,,sizeof(dis));
dis[id(S)]=;q.push(S);
while(!q.empty()){
Node p=q.top();q.pop();
if(((!p.isp)&&p.x==B[])||(p.isp&&p.x==)) return p.d;
if(flag[id(p)]) continue; if(!p.isp){
for(int i=ph[p.x];i!=-;i=poi[i][]){
if(P[poi[i][]]>SN){
if(dis[poi[i][]]<=p.d) continue;
dis[poi[i][]]=p.d;
q.push(Node(poi[i][],,p.d,));
}else if(P[poi[i][]]!=p.y){
Node x=Node(p.x,P[poi[i][]],p.d,);
if(dis[id(x)]<=p.d) continue;
dis[id(x)]=p.d;q.push(x);
}
}
if(p.y){
Node xx=Node(p.x+p.y,p.y,p.d+,);
if(p.x+p.y<N&&dis[id(xx)]>p.d+){
dis[id(xx)]=p.d+;
q.push(xx);
}xx.x=p.x-p.y;
if(p.x-p.y>=&&dis[id(xx)]>p.d+){
dis[id(xx)]=p.d+;
q.push(xx);
}
}
}
else{
for(int i=B[p.x]+P[p.x],j=;i<N;i+=P[p.x],j++){
Node a=Node(i,,p.d+j,);
if(dis[id(a)]>p.d+j){
dis[id(a)]=p.d+j;q.push(a);
}
}
for(int i=B[p.x]-P[p.x],j=;i>=;i-=P[p.x],j++){
Node a=Node(i,,p.d+j,);
if(dis[id(a)]>p.d+j){
dis[id(a)]=p.d+j;q.push(a);
}
}
}
flag[id(p)]=;
}return -;
} int main(){
//freopen(".in","r",stdin);
rei i,j,k;
N=rd(),M=rd();SN=min(,(int)sqrt(N));
memset(ph,-,sizeof(ph));
for(i=;i<M;i++){
B[i]=rd(),P[i]=rd();
poi[i][]=i;poi[i][]=ph[B[i]];ph[B[i]]=i;
}S=Node(B[],,,);
printf("%d\n",dijkstra());
return ;
}

luogu3645 [Apio2015]雅加达的摩天大楼 (分块+dijkstra)的更多相关文章

  1. [APIO2015] 雅加达的摩天楼 (分块,最短路)

    题目链接 Solution 分块+\(Dijkstra\). 难点在于建边,很明显 \(O(n^2)\) 建边会挂一堆 . 那么考虑一下, \(n^2\) 建边多余的是哪些东西 \(???\) 很显然 ...

  2. luogu P3645 [APIO2015]雅加达的摩天楼 分块 根号分治

    LINK:雅加达的摩天楼 容易想到设\(f_{i,j}\)表示第i个\(doge\)在第j层楼的最小步数. 转移显然是bfs.值得一提的是把初始某层的\(doge\)加入队列 然后转移边权全为1不需要 ...

  3. BZOJ 4070 [Apio2015]雅加达的摩天楼 ——分块 SPFA

    挺有趣的分块的题目. 直接暴力建边SPFA貌似是$O(nm)$的. 然后考虑分块,$\sqrt n$一下用虚拟节点辅助连边, 以上的直接暴力连边即可. 然后卡卡时间,卡卡空间. 终于在UOJ上T掉辣. ...

  4. bzoj 4070 [Apio2015]雅加达的摩天楼 Dijkstra+建图

    [Apio2015]雅加达的摩天楼 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 644  Solved: 238[Submit][Status][D ...

  5. 【BZOJ4070】[Apio2015]雅加达的摩天楼 set+最短路

    [BZOJ4070][Apio2015]雅加达的摩天楼 Description 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N−1.除了这 N 座摩天楼 ...

  6. BZOJ 4070:[APIO2015]雅加达的摩天楼 最短路

    4070: [Apio2015]雅加达的摩天楼 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 464  Solved: 164[Submit][Sta ...

  7. 【题解】P3645 [APIO2015]雅加达的摩天楼(分层图最短路)

    [题解]P3645 [APIO2015]雅加达的摩天楼(分层图最短路) 感觉分层图是个很灵活的东西 直接连边的话,边数是\(O(n^2)\)的过不去 然而我们有一个优化的办法,可以建一个新图\(G=( ...

  8. 洛谷P3645 [APIO2015]雅加达的摩天楼(最短路+分块)

    传送门 这最短路的建图怎么和网络流一样玄学…… 一个最朴素的想法是从每一个点向它能到达的所有点连边,边权为跳的次数,然后跑最短路(然而边数是$O(n^2)$除非自创复杂度比spfa和dijkstra还 ...

  9. BZOJ4070 [Apio2015]雅加达的摩天楼 【分块 + 最短路】

    题目链接 BZOJ4070 题解 考虑暴力建图,将每个\(B_i\)向其能到的点连边,复杂度\(O(\sum \frac{n}{p_i})\),当\(p\)比较小时不适用 考虑优化建图,每个\(dog ...

随机推荐

  1. 01-时间复杂度、对数器(python)、冒泡、选择、递归实质、归并、小和问题、逆序对、mid

    1.时间复杂度 常数时间的操作:一个操作如果和数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作. 时间复杂度为一个算法流程中,常数操作数量的指标.常用O(读作big O)来表示. 具体来说, ...

  2. 如何用区块链技术解决信任问题?Fabric 架构深度解读

    阿里妹导读:区块链技术,随着比特币的兴起而为大家所知.但是具体到技术本身,大家相对熟悉的几个词可能是“数据不可篡改”.“公开链”.“分布式数据”.“共识机制”等. 这篇文章将抛砖引玉,通过深度解读Hy ...

  3. 来不及说什么了,Python 运维开发剁手价仅剩最后 2 天

    51reboot 运维开发又双叒叕的搞活动了—— Python 运维开发 18 天训练营课程, 剁手价1299 最后2天 上课方式:网络直播/面授(仅限北京) DAY1 - DAY4 Python3 ...

  4. (理论篇)从基础文件IO说起虚拟内存,内存文件映射,零拷贝

    为了快速构建项目,使用高性能框架是我的职责,但若不去深究底层的细节会让我失去对技术的热爱. 探究的过程是痛苦并激动的,痛苦在于完全理解甚至要十天半月甚至没有机会去应用,激动在于技术的相同性,新的框架不 ...

  5. HAProxy 日志输出及配置

    正所谓,没有软件敢说没有bug,人无完人,software is  not perfect software.是软件就可能存在bug,那么如果出现bug,我们就要分析对我们业务的影响及可能如何避免bu ...

  6. Visual Studio2017 数据库架构比较

    一.前言 开发的时候在测试服务器上和线网服务器上面都有我们的数据库,当我们在线网上面修改或者新增一些字段后,线网的数据库也需要更新,这个时候根据表的修改记录,然后在线网上面一个一个增加修改很浪费效率而 ...

  7. python基础学习笔记(四)

    列表 本节继续讨论列表不同元组和字符串的地方:列表是可变的(mutable)----可以改变列表的内容,并且列表有很多有用的.专门的方法. List函数可以将一个字符串拆分成列表. >>& ...

  8. java中定时执行任务

    现在项目中用到需要定时去检查文件是否更新的功能.timer正好用于此处. 用法很简单,new一个timer,然后写一个timertask的子类即可. 代码如下: package comz.autoup ...

  9. github个人心得和链接

    github使用心得: 在本次github使用过程中,我总结了git常用命令,都有哪些功能? git常用命令: git config :配置git git add:更新working director ...

  10. Socket、Session、Option和Pipe

    消息队列NetMQ 原理分析4-Socket.Session.Option和Pipe   消息队列NetMQ 原理分析4-Socket.Session.Option和Pipe 前言 介绍 目的 Soc ...