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. scrapy爬虫框架介绍

    一 介绍 Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速.简单.可扩展的方式从网站中提取所需的数据.但目前Scrapy的用途十分广泛,可 ...

  2. WPF之模拟打开或关闭Windows功能

    用WPF模拟打开或关闭Windows功能的实现方法其实很简单,主要用递归判断当前节点的子节点和父节点的选中状态就行了. 一.效果演示 先看看效果图: 二.部分代码 xaml代码: <TreeVi ...

  3. pip安装模块时:error: command 'gcc' failed with exit status 1

    用安装python模块出现error: command 'gcc' failed with exit status 1 问题: gcc编译缺少模块 解决方法: yum install gcc libf ...

  4. python开发web服务器——搭建简易网站

    参看:https://blog.csdn.net/baidu_35085676/article/details/69807145

  5. Hadoop(一):概述

    一.Hadoop是什么? Hadoop是一个由Apache基金会所开发的分布式系统基础架构.Hadoop框架最核心的设计包含两个方面,一是分布式文件系统(Hadoop Distributed File ...

  6. linux下rz,sz安装

    1.sz rz yum安装 yum install lrzsz

  7. C语言实现knn

    以后写代码一定要谨慎,提高代码的正确率. /*************************************** * 1.初始化距离为最大值 * 2.计算未知样本和每个训练样本的距离为dis ...

  8. Kaggle:Titanic: Machine Learning from Disaster

    一直想着抓取股票的变化,偶然的机会在看股票数据抓取的博客看到了kaggle,然后看了看里面的题,感觉挺新颖的,就试了试. 题目如图:给了一个train.csv,现在预测test.csv里面的Passa ...

  9. kali&BT安装好之后无法上网(包括Wifi)或者无法获得内网IP解决方法

    大家都知道,要想进行内网渗透攻击,你必须要在那个内网里.但是大家在Vmware里安装kali的时候,大多数用户为了方便,未选择桥接模式,而是选择了使用与本机共享的IP网络当然,这样能上网,但是你的虚拟 ...

  10. 如何让EasyUI弹出层跳出框架

    这个的解决方法其实挺简单的. 只要在最外面的框架页面加个div,然后用parent.div的id就可以的.但是必须得弹出框得是一个页面. <div id="div_info" ...