BZOJ_3073_[Pa2011]Journeys_线段树优化建图+BFS
BZOJ_3073_[Pa2011]Journeys_线段树优化建图+BFS
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
1 2 4 5
5 5 4 4
1 1 3 3
Sample Output
1
1
2
0
1
1
2
0
1
有一个朴素的方法:对(a,b)中的点对一个新建节点连边边权为0,对另一个新建节点连边权为1,另一个新建节点向(c,d)中的所有节点连边。
用线段树优化一下:
开两个线段树A,B,其中A中的节点向父亲连边,B中节点向儿子连边。B中叶子向A中叶子连边。
然后把(a,b)中的点替换成线段树上的log个节点,和上面的连边方法相同。
跑最短路即可,由于边权是0,1可以BFS上去。
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 500050 #define M 4000050 int Q[M],tot,l,r,ls[N<<3],rs[N<<3]; int head[M][2],to[M<<2][2],nxt[M<<2][2],cnt,idx[N],n,m,a[N<<3],dis[M],rta,rtb,b[N<<3]; inline void add(int u,int v,int w) { to[++cnt][w]=v; nxt[cnt][w]=head[u][w]; head[u][w]=cnt; } void build(int l,int r,int &p,int flg) { p=++tot; if(l==r) { if(!flg) idx[l]=p; else b[l]=p; return ; } int mid=(l+r)>>1; build(l,mid,ls[p],flg); build(mid+1,r,rs[p],flg); if(!flg) { add(ls[p],p,0); add(rs[p],p,0); }else { add(p,ls[p],0); add(p,rs[p],0); } } void update(int l,int r,int x,int y,int p) { if(x<=l&&y>=r) { a[++a[0]]=p; return ; } int mid=(l+r)>>1; if(x<=mid) update(l,mid,x,y,ls[p]); if(y>mid) update(mid+1,r,x,y,rs[p]); } void link(int x,int y,int z,int w) { tot++; update(1,n,x,y,rta); int i; for(i=1;i<=a[0];i++) add(a[i],tot,0); a[0]=0; tot++; add(tot-1,tot,1); update(1,n,z,w,rtb); for(i=1;i<=a[0];i++) add(tot,a[i],0); a[0]=0; } void dfs(int x,int y) { if(dis[x]) return ; dis[x]=y; Q[r++]=x; int i; for(i=head[x][0];i;i=nxt[i][0]) dfs(to[i][0],y); } int main() { int S;int i,x,y,z,w; scanf("%d%d%d",&n,&m,&S); rta=0,rtb=0; build(1,n,rta,0); build(1,n,rtb,1); for(i=1;i<=n;i++) add(b[i],idx[i],0); for(i=1;i<=m;i++) { scanf("%d%d%d%d",&x,&y,&z,&w); link(x,y,z,w); link(z,w,x,y); } dfs(idx[S],1); while(l<r) { x=Q[l++];y=dis[x]+1; for(i=head[x][1];i;i=nxt[i][1]) dfs(to[i][1],y); } for(i=1;i<=n;i++) { printf("%d\n",dis[idx[i]]-1); } }