[bzoj3073]Journeys
https://www.zybuluo.com/ysner/note/1295471
题面
\(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\)号国家能到任意一个国家。
- \(n\leq5*10^5,m\leq10^6\)
解析
显然不能照着题面说的去建边啊,空间复杂度\(O(n^2)\)惹不起。
一般来说,当边数过多的时候,一般都有一种使边数变少的方法:线段树优化连边。
首先要有两颗线段树,一颗维护出发区间,一颗维护到达区间。(要不然会重复)
如果要在对应的两个区间建边,可以建单向边,从一个区间(线段树)向一个新建点连边,边权赋为\(1\);再把这点连向另一个区间(线段树),边权赋为\(0\)。
如果要建反向边,再新建一个点就可以了。
(理性思考一下发现与题目意思是等价的)
在出发线段树内部,由子结点向父结点建边;在到达线段树内部,由父结点向子结点建边。边权均为\(0\)。毕竟区间内部移动应该是(可看为)不需要经过道路的。
然后两颗线段树对应结点建边权为\(0\)的双向边。
所以这个建边的空间复杂度是多少呢?
线段树内部建边\(O(2nlogn)\),线段树对应点连边\(O(nlogn)\),区间建边\(O(m*?)\)。
所以建边数组要使劲往大开。
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define re register
#define il inline
#define ls x<<1
#define rs x<<1|1
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1e7+100;
int n,m,p,st[N],ed[N],id[2][N],tot,h[N],cnt,dis[N];
bool vis[N];
struct Edge{int to,nxt,w;}e[N];
il void add(re int u,re int v,re int w){e[++cnt]=(Edge){v,h[u],w};h[u]=cnt;}
struct node{int u,dis;il bool operator < (const node &o) const {return dis>o.dis;}};
priority_queue<node>Q;
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void Build(re int x,re int l,re int r)
{
id[0][x]=++tot;id[1][x]=++tot;
if(l==r)
{
st[l]=id[0][x];ed[l]=id[1][x];
add(id[0][x],id[1][x],0);
add(id[1][x],id[0][x],0);
return;
}
re int mid=l+r>>1;
Build(ls,l,mid);Build(rs,mid+1,r);
add(id[0][ls],id[0][x],0);add(id[0][rs],id[0][x],0);
add(id[1][x],id[1][ls],0);add(id[1][x],id[1][rs],0);
}
il void Insert(re int x,re int l,re int r,re int ql,re int qr,re int u,re int op)
{
if(ql<=l&&r<=qr)
{
if(!op) add(id[0][x],u,1);
else add(u,id[1][x],0);
return;
}
re int mid=l+r>>1;
if(ql<=mid) Insert(ls,l,mid,ql,qr,u,op);
if(qr>mid) Insert(rs,mid+1,r,ql,qr,u,op);
}
il void Dijstra()
{
memset(dis,63,sizeof(dis));
Q.push((node){st[p],0});dis[st[p]]=0;
while(!Q.empty())
{
re int u=Q.top().u;Q.pop();
vis[u]=1;
for(re int i=h[u];i;i=e[i].nxt)
{
re int v=e[i].to;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
Q.push((node){v,dis[v]});
}
}
while(!Q.empty()&&vis[Q.top().u]) Q.pop();
}
}
int main()
{
n=gi();m=gi();p=gi();
Build(1,1,n);
fp(i,1,m)
{
re int A=gi(),B=gi(),C=gi(),D=gi();
++tot;
Insert(1,1,n,A,B,tot,0);
Insert(1,1,n,C,D,tot,1);
++tot;
Insert(1,1,n,C,D,tot,0);
Insert(1,1,n,A,B,tot,1);
}
Dijstra();
fp(i,1,n) printf("%d\n",dis[ed[i]]);
return 0;
}
然而时间不够优秀。。。
注意到边权只有\(0/1\),我们实际上可以优化最短路算法中的那个\(log\)。
每次更新完,我们可以把为\(0\)的放在队首,为\(1\)的放在队尾。因为从\(0\)转移过来的肯定比从\(1\)的更优。
il void Dijstra()
{
memset(dis,63,sizeof(dis));
Q.push_back(st[p]);dis[st[p]]=0;
while(!Q.empty())
{
re int u=Q.front();Q.pop_front();
if(vis[u]) continue;vis[u]=1;
for(re int i=h[u];i;i=e[i].nxt)
{
re int v=e[i].to;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
e[i].w?Q.push_back(v):Q.push_front(v);
}
}
}
}
[bzoj3073]Journeys的更多相关文章
- BZOJ3073 Journeys - 线段树优化建边
传送门 题意: Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路: ...
- [bzoj3073] Journeys 题解(线段树优化建图)
Description Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建 ...
- 【BZOJ3073】[Pa2011]Journeys 线段树+堆优化Dijkstra
[BZOJ3073][Pa2011]Journeys Description Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在 ...
- bzoj3073: [Pa2011]Journeys 线段树优化建图
bzoj3073: [Pa2011]Journeys 链接 BZOJ 思路 区间和区间连边.如何线段树优化建图. 和单点连区间类似的,我们新建一个点,区间->新点->区间. 又转化成了单点 ...
- BZOJ3073 : [Pa2011]Journeys
用线段树套链表维护所有边,用set维护未访问过的点 然后BFS,每次在线段树上找边,然后在set中查询点 一条边使用之后就没有用了,所以在链表中将它删去 时间复杂度$O((n+m)\log n+m\l ...
- 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra
题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a, ...
- BZOJ3073: [Pa2011]Journeys(线段树优化建图 Dijkstra)
题意 \(n\)个点的无向图,构造\(m\)次边,求\(p\)到任意点的最短路. 每次给出\(a, b, c, d\) 对于任意\((x_{a \leqslant x \leqslant b}, y_ ...
- BZOJ3073 [Pa2011]Journeys[最短路—线段树优化建边]
新技能get✔. 线段树优化建边主要是针对一类连续区间和连续区间之间建边的题,建边非常的优秀.. 这题中,每次要求$[l1,r1]$每一点向$[l2,r2]$每一点建无向边,然后单元最短路. 暴力建边 ...
- bzoj 3073: [Pa2011]Journeys -- 线段树优化最短路
3073: [Pa2011]Journeys Time Limit: 20 Sec Memory Limit: 512 MB Description Seter建造了一个很大的星球,他准备建 ...
随机推荐
- Linux中CentOS网络配置以及与Xshell建立远程连接
为centos配置网络 (1)第一步 点开虚拟机的设置,如下图做相关的设置: 网络连接要选择桥接模式,其他的勾选就按照上图的即可,勾选完成点击确定. (2)第二步 点击VMware的编辑选项,找到“虚 ...
- linux 批量修改文件名 文件名只保留部分,去掉部分
问题:linux系统中文件名包含中文,导致页面访问不了文件.就是上条博客中的解决方法二遗留问题. 文件名中有以下格式:TC2_诺而达铜管(中山)有限公司.pdf ,要改为TC2.pdf,去掉中文部分 ...
- Python Pandas库的学习(二)
今天我们继续讲下Python中一款数据分析很好的库.Pandas的学习 接着上回讲到的,如果有人听不懂,麻烦去翻阅一下我前面讲到的Pandas学习(一) 如果我们在数据中,想去3,4,5这几行数据,那 ...
- add list of symbols -- latex
* add list of symbols -- latexinclude a *toc.tex* file in the *main.tex* in *main.tex*#+BEGIN_SRC la ...
- Python+selenium下拉菜单选项
案例:在我要自学网登录页面选择要保留的时间 具体页面如图所示: 使用前端工具查看部分页面代码: <select class="loinp" name="Cookie ...
- C++ fill 和memset
以下内容来自www.cplusplus.com--------------------------------------------------- FILL: template <class ...
- mvnw是什么(Maven Wrapper/Maven保持构建工具版本一直的工具)
背景 Maven是一款非常流行的Java项目构建软件,它集项目的依赖管理.测试用例运行.打包.构件管理于一身,是我们工作的好帮手,maven飞速发展,它的发行版本也越来越多,如果我们的项目是基于Mav ...
- linux 实现VLAN
本文将在一台linux机器上,利用linuxbridge 等技术模拟创建VLAN 环境. 首先,创建vlan interface ip link add link ens33 name ens33.8 ...
- struts1与struts2的差别
Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架.其全新的Struts 2的体系结构与Struts 1的体系结 ...
- HDU 3280 Equal Sum Partitions(二分查找)
Equal Sum Partitions Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...