[bzoj3073][Pa2011]Journeys 線段樹優化建邊的最短路

3073: [Pa2011]Journeys

Time Limit: 20 Sec  Memory Limit: 512 MB
[Submit][Status][Discuss]

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

由於不知道怎麼用線段樹加邊,借鑑了一下其他人的做法
主要思路是搞兩棵線段樹
不是用來維護東西,而是在上面建邊
一個線段樹上的節點代表它在線段樹上代表的區間的所有點
一棵線段樹表示進(從小區間到大區間),另一顆表示出
所以進來的線段樹son->fa 長度爲0
出去的線段樹fa->son長度爲0
共用虛點,
進來的線段樹->虛點 長度爲1
虛點->出去的線段樹長度爲1
跑最短路,記錄原圖中每一個節點在出線段樹中的編號,輸出要除2
#include <bits/stdc++.h>
#define pa pair<int,int>
using namespace std;
const int N = 30000005;
int n, m, S, cnt, vir, last[5000000], dis[5000000], vis[5000000], pos[5000000];
struct Edge{ int to, next, v; } e[N];
void insert( int u, int v, int w ){ e[++cnt].to = v; e[cnt].v = w; e[cnt].next = last[u]; last[u] = cnt; }
/*
	flag 0 -> father in
		 1 -> son    out
*/
struct Seg_Tree{
	void build( int k, int l, int r, int flag ){
		if( l == r ){
			if( !flag ) pos[l] = k;
			else insert( (n<<2) + k, k, 0 );
			return ;
		}
		int mid = l + r >> 1;
		build( k<<1, l, mid, flag );
		build( k<<1|1, mid+1, r, flag );
		if( flag ) insert( (n<<2) + k, (n<<2) + (k<<1), 0 ), insert( (n<<2) + k, (n<<2) + (k<<1|1), 0 );
		else       insert( k<<1, k, 0 ), insert( k<<1|1, k, 0 );
	}
	void update( int k, int l, int r, int L, int R, int a, int flag ){
		if( L <= l && r <= R ){
			if( flag ) insert( a, k + (n<<2), 1 );
			else	   insert( k, a, 1 );
			return ;
		}
		int mid = l + r >> 1;
		if( L <= mid ) update( k<<1, l, mid, L, R, a, flag );
		if( R >  mid ) update( k<<1|1, mid+1, r, L, R, a, flag );
	}
} t1, t2;
priority_queue< pa, vector<pa>, greater<pa> > q;
void dijkstra(){
	memset( dis, 63, sizeof(dis) );
	q.push(make_pair(0,pos[S])); dis[pos[S]] = 0; vis[pos[S]] = 1;
	while( !q.empty() ){
		int now = q.top().second; q.pop();
		for( int i = last[now]; i; i = e[i].next )
			if( dis[e[i].to] > dis[now] + e[i].v ){
				dis[e[i].to] = dis[now] + e[i].v;
				if( !vis[e[i].to] ) q.push(make_pair(dis[e[i].to],e[i].to)), vis[e[i].to] = 1;
			}
	}
}
int main(){
	scanf( "%d%d%d", &n, &m, &S ); vir = n<<3;
	t1.build( 1, 1, n, 0 ); t2.build( 1, 1, n, 1 );
	for( int i = 1, a, b, c, d; i <= m; i++ ){
		scanf( "%d%d%d%d", &a, &b, &c, &d );
		t1.update( 1, 1, n, a, b, ++vir, 0 ), t2.update( 1, 1, n, c, d, vir, 1 );
		t1.update( 1, 1, n, c, d, ++vir, 0 ), t2.update( 1, 1, n, a, b, vir, 1 );
	}
	dijkstra();
	for( int i = 1; i <= n; i++ ) printf( "%d\n", dis[pos[i]]>>1 );
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章