3073: [Pa2011]Journeys

Time Limit: 20 Sec  Memory Limit: 512 MB

Description

 
 
Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路。N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路。Seter保证一条道路不会修建两次,也保证不会有一个国家与自己之间有道路。
Seter好不容易建好了所有道路,他现在在位于P号的首都。Seter想知道P号国家到任意一个国家最少需要经过几条道路。当然,Seter保证P号国家能到任意一个国家。
 
 
 
注意:可能有重边

Input

 
第一行三个数N,M,P。N<=500000,M<=100000。
后M行,每行4个数A,B,C,D。1<=A<=B<=N,1<=C<=D<=N。
 
 
 

Output

 
N行,第i行表示P号国家到第i个国家最少需要经过几条路。显然第P行应该是0。
 
 

Sample Input

5 3 4
1 2 4 5
5 5 4 4
1 1 3 3

Sample Output

1
1
2
0
1

HINT

我们发现本题点数非常多,需要建的边也非常多,如果直接建图的话一定会TLE+MLE

但是我们会发现本题有一个很好的性质,就是连续一段区间都可以到达另外连续一段区间

如何优化这样连续的区间,我们就会想到一种数据结构——线段树

我们可以将线段树一段区间映射到这里,这样就可以用线段树上的几段完整表示整个区间,这也可以看成将点打包的思想

接下来我们考虑如何从【a,b】到【c,d】连边

首先,如果我们还是直接将每段线段连边的话它的复杂度还是很高

所以我们考虑抽象成新建两个点P1,P2,表示两段区间,这样从【a,b】到【c,d】,就是相当于从P1到P2连一条边

然后我们只要所有线段【a,b】向P1连边,P2向所有线段【c,d】连边就可以做到了

但是,这里还存在一个问题,就是如果把图建到一棵线段树中就会出现线段重叠,就会出问题

所以我们需要建两棵线段树A,B,表示从A会经过一条P边到B,这样就可以表示经过了一条边

然后我们对于A线段树中的点从儿子向父亲连一条权值为0的边(因为它本身属于这个集合,不需要代价)

从B线段树中的爹向儿子连一条权值为0的边(因为能到爹一定也能到儿子,不需要代价)

再从B中的叶子节点向A中对应叶子节点连一条权值为0的边(走完一条路径,到达对应点,继续从它开始出发)

这样,我们就可以跑最短路了

#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 1000000007
#define ll long long
#define M 4000010
#define N 500010
inline int rd()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
int n,m,p;
int lj[M],to[M<<],v[M<<],fro[M<<],cnt,ls[N<<],rs[N<<],ra,rb,tot,val[N],dis[M];
inline int add(int a,int b,int c){fro[++cnt]=lj[a];to[cnt]=b;v[cnt]=c;lj[a]=cnt;}
void build(int l,int r,int &x,int op)
{
x=++tot;
if(l==r){if(op) val[l]=x;return;}
int mid=l+r>>;
build(l,mid,ls[x],op);build(mid+,r,rs[x],op);
if(op) add(ls[x],x,),add(rs[x],x,);
else add(x,ls[x],),add(x,rs[x],);
}
void fadd(int l,int r,int x,int y)
{
if(l==r){add(y,x,);return;}
int mid=l+r>>;
fadd(l,mid,ls[x],ls[y]);fadd(mid+,r,rs[x],rs[y]);
}
void padd(int l,int r,int p,int L,int R,int x,int op)
{
if(L==l&&R==r)
{
if(op) add(x,p,);
else add(p,x,);
return;
}
int mid=l+r>>;
if(L>mid) padd(mid+,r,p,L,R,rs[x],op);
else if(R<=mid) padd(l,mid,p,L,R,ls[x],op);
else
{
padd(l,mid,p,L,mid,ls[x],op);
padd(mid+,r,p,mid+,R,rs[x],op);
}
}
void link(int a,int b,int c,int d)
{
padd(,n,++tot,a,b,ra,);add(tot,tot+,);
padd(,n,++tot,c,d,rb,);
}
#define pa pair<int,int>
priority_queue<pa,vector<pa >,greater<pa > >q;
bool vs[M];
void dij()
{
memset(dis,0x3f,sizeof(dis));
int l=,r=,x;
dis[val[p]]=;
q.push(make_pair(,val[p]));
while(!q.empty())
{
x=q.top().second;q.pop();
if(vs[x]) continue;vs[x]=;
for(int i=lj[x];i;i=fro[i])
if(dis[to[i]]>dis[x]+v[i])
{
dis[to[i]]=dis[x]+v[i];
q.push(make_pair(dis[to[i]],to[i]));
}
}
}
int main()
{
int a,b,c,d;
n=rd();m=rd();p=rd();
build(,n,ra,);build(,n,rb,);fadd(,n,ra,rb);
for(int i=;i<=m;i++)
{
a=rd();b=rd();c=rd();d=rd();
link(a,b,c,d);link(c,d,a,b);
}
dij();
for(int i=;i<=n;i++) printf("%d\n",dis[val[i]]);
return ;
}

bzoj 3073: [Pa2011]Journeys -- 线段树优化最短路的更多相关文章

  1. bzoj 3073 [Pa2011]Journeys ——线段树优化连边

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3073 建两棵线段树,一棵孩子向父亲连边,是走出去的:一棵父亲向孩子连边,是走进来的. 注意第 ...

  2. 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

    题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a, ...

  3. BZOJ3073: [Pa2011]Journeys(线段树优化建图 Dijkstra)

    题意 \(n\)个点的无向图,构造\(m\)次边,求\(p\)到任意点的最短路. 每次给出\(a, b, c, d\) 对于任意\((x_{a \leqslant x \leqslant b}, y_ ...

  4. BZOJ_3073_[Pa2011]Journeys_线段树优化建图+BFS

    BZOJ_3073_[Pa2011]Journeys_线段树优化建图+BFS Description Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N ...

  5. 【BZOJ3073】[Pa2011]Journeys 线段树+堆优化Dijkstra

    [BZOJ3073][Pa2011]Journeys Description Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在 ...

  6. 【题解】Journeys(线段树优化连边)

    [#3073. Pa2011]Journeys (线段树优化连边) 这张图太直观了,直接讲透了线段树优化连边的原理和正确性. 考虑建立两颗线段树,一颗是外向树,一颗是内向树,相当于网络流建模一样,我们 ...

  7. DS线段树优化最短路&&01bfs浅谈

    1简介 为什么需要?原因很简单,当需要有大量的边去连时,用线段树优化可以直接用点连向区间,或从区间连向点,或从区间连向区间,如果普通连边,复杂度是不可比拟的.下面简单讲解一下线段树(ST)优化建图. ...

  8. bzoj 3073 Journeys —— 线段树优化连边

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3073 建两棵线段树,一棵从下往上连边,一棵从上往下连边,叶子节点之间也有连边: 区间向区间连 ...

  9. BZOJ 3073: [Pa2011]Journeys Dijkstra+线段树优化建图

    复习一下线段树优化建图:1.两颗线段树的叶子节点的编号是公用的. 2.每次连边是要建两个虚拟节点 $p1,p2$ 并在 $p1,p2$ 之间连边. #include <bits/stdc++.h ...

随机推荐

  1. 详解H5中的history单页面,手动实现单页面开发,细说h5单页面原理

    就目前来看,前端的单页面开发占了很大一部分,一方面无刷新的切换增强了体验,并且浏览器记录依然存在,前进后退都没问题,在之前我们通地址栏中的hash改变来触发onhashchange方法来实现单页面应用 ...

  2. jQuery()方法的第二个参数详解

    关于jQuery()方法的第二个参数,有下面这几种用法: 1.jQuery(selector, [context]) 这种用法,相当于 $(context).find(selector) 或者 con ...

  3. linux 下 genymotion 模拟器不能安装app

    提示: "应用未安装" 解决方法: 下载: Genymotion-ARM-Translation_v1.1.zip 进入genymotion 的tools用adb传进去: ./ad ...

  4. gmail注册时“此电话号码无法用于进行验证”

    网上有几个方法,有说不要改默认地点,有说验证时直接写+86手机号,试了以后还是不行. 我的方法:换成IE浏览器,就可以验证了.

  5. 【Python学习】字符编码

    先说两个基础知识. (1)计算机内部,数据是由0,1组成的: (2)计算机最小的数据单位,就是一个二进制单位即bit,接下来就是8个二进制单位表示一个字节(Byte). 1 ASCII码 ASCII码 ...

  6. C++ Class与Struct的区别

    转自某楼层的回复http://bbs.csdn.net/topics/280085643 首先,讨论这个问题应该仅从语法上讨论,如果讨论不同人之间编程风格上的差异,那这个问题是没有答案的.毕竟不同的人 ...

  7. CentOS中搭建Redis伪分布式集群【转】

    解压redis 先到官网https://redis.io/下载redis安装包,然后在CentOS操作系统中解压该安装包: tar -zxvf redis-3.2.9.tar.gz 编译redis c ...

  8. easyui datagrid 去掉 全选checkbox

    在加载 表格的时候添加事件:onLoadSuccess 在事件中写入下面句,用空代替原有HTML 达到取消效果. $(".datagrid-header-check").html( ...

  9. Delphi XE增强的RTTI妙用--动态创建包中的窗口类

    以前要在运行时创建package中的form类,必须要在form单元文件中这样注册类: Initialization  RegisterClass(TForm3);Finalization  UnRe ...

  10. hbase学习(二)hbase单机和高可用完全分布式安装部署

    hbase版本 2.0.4  与hadoop兼容表http://hbase.apache.org/book.html#hadoop  我的 hadoop版本是3.1   1.单机版hbase 1.1解 ...