题目描述

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,M,P。N<=500000,M<=100000。
后M行,每行4个数A,B,C,D。1<=A<=B<=N,1<=C<=D<=N。

输出

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

样例输入

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

样例输出

1
1
2
0
1


题解

线段树优化建图+堆优化Dijkstra

看别人blog看到了这道题,于是决定YY一发。

一个朴素(已经不是最朴素的了)的加边方法:a~b的所有点->p1,长度为0;p1->p2,长度为1;p2->c~d的所有点,长度为0,其中加的都是有向边,p1和p2是新建的两个辅助点,然后再反过来进行这个过程。

然而这样加边的话边数依旧巨大。

由于给出的加边都是区间形式,所以我们可以用维护区间的数据结构——线段树,去优化这个建图过程。

具体方法(这里只讲加有向边a~b->c~d的方法):

建立两颗线段树A、B,其中A线段树每个非叶子节点的儿子向该节点连边,长度为0,B线段树每个非叶子节点向该节点的儿子连边,长度为0;B线段树的叶子结点向A线段树对应的叶子结点连边,长度为0。

这里面A线段树的叶子结点代表原图中的节点,其余节点都是用来优化建图。

对于加边操作,找到A线段树上a~b对应的区间节点,这些节点向p1连边,长度为0;p1->p2,长度为1;找到B线段树上c~d对应的区间节点,p2向这些节点连边,长度为0.

最后跑堆优化Dijkstra出解。

应该不是很难理解,具体可以见代码。

#include <cstdio>
#include <cstring>
#include <queue>
#include <utility>
#define N 500010
#define M 3500010
using namespace std;
priority_queue<pair<int , int> > q;
int head[M] , to[M << 3] , len[M << 3] , next[M << 3] , cnt , ls[N << 3] , rs[N << 3] , ra , rb , tot , v[N] , n , dis[M] , vis[M];
void add(int x , int y , int z)
{
to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
}
void build(int l , int r , int &x , int flag)
{
x = ++tot;
if(l == r)
{
if(flag) v[l] = x;
return;
}
int mid = (l + r) >> 1;
build(l , mid , ls[x] , flag) , build(mid + 1 , r , rs[x] , flag);
if(flag) add(ls[x] , x , 0) , add(rs[x] , x , 0);
else add(x , ls[x] , 0) , add(x , rs[x] , 0);
}
void deal(int l , int r , int x , int y)
{
if(l == r)
{
add(y , x , 0);
return;
}
int mid = (l + r) >> 1;
deal(l , mid , ls[x] , ls[y]) , deal(mid + 1 , r , rs[x] , rs[y]);
}
void update(int b , int e , int p , int l , int r , int x , int flag)
{
if(b <= l && r <= e)
{
if(flag) add(x , p , 0);
else add(p , x , 0);
return;
}
int mid = (l + r) >> 1;
if(b <= mid) update(b , e , p , l , mid , ls[x] , flag);
if(e > mid) update(b , e , p , mid + 1 , r , rs[x] , flag);
}
void link(int a , int b , int c , int d)
{
update(a , b , ++tot , 1 , n , ra , 1) , add(tot , tot + 1 , 1) , update(c , d , ++tot , 1 , n , rb , 0);
}
int main()
{
int m , p , a , b , c , d , i , x;
scanf("%d%d%d" , &n , &m , &p);
build(1 , n , ra , 1) , build(1 , n , rb , 0) , deal(1 , n , ra , rb);
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d%d" , &a , &b , &c , &d) , link(a , b , c , d) , link(c , d , a , b);
memset(dis , 0x3f , sizeof(dis)) , dis[v[p]] = 0 , q.push(make_pair(0 , v[p]));
while(!q.empty())
{
x = q.top().second , q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(dis[to[i]] > dis[x] + len[i])
dis[to[i]] = dis[x] + len[i] , q.push(make_pair(-dis[to[i]] , to[i]));
}
for(i = 1 ; i <= n ; i ++ ) printf("%d\n" , dis[v[i]]);
return 0;
}

【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra的更多相关文章

  1. bzoj3073: [Pa2011]Journeys 线段树优化建图

    bzoj3073: [Pa2011]Journeys 链接 BZOJ 思路 区间和区间连边.如何线段树优化建图. 和单点连区间类似的,我们新建一个点,区间->新点->区间. 又转化成了单点 ...

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

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

  3. 洛谷 P5471 - [NOI2019] 弹跳(二维线段树优化建图+堆优化存边)

    题面传送门 一道非常有意思的题(大概可以这么形容?) 首先看到这类一个点想一个区域内连边的题目可以很自然地想到线段树优化建图,只不过这道题是二维的,因此需要使用二维线段树优化建图,具体来说,我们外层开 ...

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

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

  5. bzoj 3073: [Pa2011]Journeys -- 线段树优化最短路

    3073: [Pa2011]Journeys Time Limit: 20 Sec  Memory Limit: 512 MB Description     Seter建造了一个很大的星球,他准备建 ...

  6. Codeforces.786B.Legacy(线段树优化建图 最短路Dijkstra)

    题目链接 \(Description\) 有\(n\)个点.你有\(Q\)种项目可以选择(边都是有向边,每次给定\(t,u,v/lr,w\)): t==1,建一条\(u\to v\)的边,花费\(w\ ...

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

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

  8. BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan

    Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...

  9. HDU 5669 线段树优化建图+分层图最短路

    用线段树维护建图,即把用线段树把每个区间都标号了,Tree1中子节点有到达父节点的单向边,Tree2中父节点有到达子节点的单向边. 每次将源插入Tree1,汇插入Tree2,中间用临时节点相连.那么T ...

随机推荐

  1. Codeforces Round #319 (Div. 2) B Modulo Sum (dp,鸽巢)

    直接O(n*m)的dp也可以直接跑过. 因为上最多跑到m就终止了,因为前缀sum[i]取余数,i = 0,1,2,3...,m,有m+1个余数,m的余数只有m种必然有两个相同. #include< ...

  2. FMDB浅析(思想)

    http://www.cnblogs.com/OTgiraffe/p/5931800.html 一.FMDB介绍 FMDB是一种第三方的开源库,FMDB就是对SQLite的API进行了封装,加上了面向 ...

  3. 为DataGridView控件实现复选功能

    实现效果: 知识运用: DataGridViewCheckBoxColumn类 实现代码: private class Fruit { public int Price { get; set; } p ...

  4. 2018.4.9 Ubuntu install kreogist-mu

    先下载kreogist m文件 然后在下载哪里右键点击打开终端 输入sudo dpkg -i + 文件名 输入密码 下一步会显示 未安装未安装软件包 libmpv1. jiexialai要处理 sud ...

  5. web.xml 中 resource-ref 的注意事项

    配置说明: web.xml 中配置 <resource-ref> <description>Employees Database for HR Applications< ...

  6. IOS中将颜色转换为image

    - (UIImage *)createImageWithColor:(UIColor *)color { CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f ...

  7. TypeError: Cannot read property 'tap' of undefined

    E:\vue-project\vue-element-admin-master>npm run build:prod vue-element-admin@3.8.1 build:prod E:\ ...

  8. cin 和 getline 混用中需要注意的问题

    这段时间在刷题过程中遇到一个cin和getline混合使用中的问题,解决之后记录如下: 先来看一段代码 #include <iostream> #include <string> ...

  9. 【思维题 费用流 技巧】bzoj5403: marshland

    主要还是网络流拆点建图一类技巧吧 Description JudgeOnline/upload/201806/1(4).pdf 题目分析 第一眼看到这题时候只会把每个点拆成4个方向:再强制定向连边防止 ...

  10. fread()创建文件和file_exists()文件缓存问题

    ①fread('','w')调用当文件不存在时创建文件,其中参数使用了fread('',"w")导致无法创建文件,修改单引号之后操作正常. ②项目当中新建日志文件,需要判断日志文件 ...