BZOJ3073: [Pa2011]Journeys

题解:  暴力建图当然gg 我们考虑用线段树分块建图的思想 因为涉及到两个区间 对着建图 一个线段树不够 考虑用两个线段树 一个作为出树(出树儿子向父亲连边) 一个作为入树(父亲向儿子连边) 每次出树向入树连边 这样建图的话也是mlogn^2的 显然还可以优化 我们采用对于每次连边 用一个超级大源点 这样的话每次连边为log^n级别的 然后对于入树而言 他可以和出树平行连边 这样的话 在本质上 还是两个区间直接产生贡献=>等价于从出树的x节点->入树的y节点->出树的y节点 这样连边跑spfa统计入树答案即可

#include <bits/stdc++.h>
#define mp make_pair
const int MAXN=8e5+10;
const int inf=1e9;
using namespace std;
vector<pair<int,int> >vec[MAXN<<3];
int pos[MAXN],sz,S,n,m,p;
void built(int rt,int l,int r){
	if(l==r){pos[l]=rt;return ;}
	vec[rt<<1].push_back(mp(rt,0));
	vec[rt<<1|1].push_back(mp(rt,0));
	int mid=(l+r)>>1;
	built(rt<<1,l,mid);
	built(rt<<1|1,mid+1,r);
}
void built1(int rt,int l,int r){
	vec[rt+sz].push_back(mp(rt,0));
	if(l==r)return ;
	vec[rt+sz].push_back(mp((rt<<1)+sz,0));vec[rt+sz].push_back(mp((rt<<1|1)+sz,0));
	int mid=(l+r)>>1;
	built1(rt<<1,l,mid);
	built1(rt<<1|1,mid+1,r);
}
void addedge(int rt,int l,int r,int ql,int qr,int vul){
	if(ql<=l&&r<=qr){
		if(vul>0)vec[rt].push_back(mp(S,1));
		else vec[S].push_back(mp(rt+sz,0));
		return ;
	}
	int mid=(l+r)>>1;
	if(ql<=mid)addedge(rt<<1,l,mid,ql,qr,vul);
	if(qr>mid)addedge(rt<<1|1,mid+1,r,ql,qr,vul);
}
int dis[MAXN<<3];bool vis[MAXN<<3];
queue<int>que;
void spfa(int t){
	for(int i=0;i<=S;i++)dis[i]=inf,vis[i]=0;
	que.push(t);vis[t]=1;dis[t]=dis[t+sz]=0;
	while(!que.empty()){
		int t1=que.front();que.pop();vis[t1]=0;
		for(int i=0;i<vec[t1].size();i++){
			if(dis[vec[t1][i].first]>dis[t1]+vec[t1][i].second){
				dis[vec[t1][i].first]=dis[t1]+vec[t1][i].second;
				if(!vis[vec[t1][i].first]){vis[vec[t1][i].first]=1;que.push(vec[t1][i].first);}
			}
		}
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&p);S=(n<<3);
	sz=(n<<2);built(1,1,n);built1(1,1,n);
	int a,b,c,d;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d%d",&a,&b,&c,&d);
		S++;
		addedge(1,1,n,a,b,1);addedge(1,1,n,c,d,0);
		S++;
		addedge(1,1,n,c,d,1);addedge(1,1,n,a,b,0);
	}
	spfa(pos[p]);
	for(int i=1;i<=n;i++)printf("%d\n",dis[pos[i]+sz]);
}

 

3073: [Pa2011]Journeys

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 634  Solved: 191
[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

Source

posted @ 2018-08-15 00:46  wang9897  阅读(162)  评论(0编辑  收藏  举报