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。
将点建成两棵线段树,记为A,B,以后所有连边为单向边,A中每个节点到父节点连单向边,边权0,B中每个节点到子节点连边,边权0,B中每个节点到A中相同位置的点连边,边权0,对每一组边,新开一个节点x,在A中查出[a,b]对应的点,到x连边,边权1/2,x到B中[c,d]对应的点连边,边权1/2
新建的图中A中的叶节点对应了原图中的点,在原图中走一条边对应新图中从A的叶节点出发,经过一个x节点,到达B,再走回A
然后就是01边权最短路了。。可以用dijkstra+deque维护,时空复杂度都和边数同阶,为O(Mlogn+n)
#include<bits/stdc++.h> char buf[10000007],*ptr=buf-1; int _(){ int x=0,c=*++ptr; while(c<48)c=*++ptr; while(c>47)x=x*10+c-48,c=*++ptr; return x; } int n,m,k,mx=2; int l[2555555],idp; bool d[2555555],ev[30000007]; int es[30000007],enx[30000007],e0[2555555],ep=2; void ae(int a,int b,int c){ es[ep]=b;enx[ep]=e0[a];ev[ep]=c;e0[a]=ep++; } void ins1(int l,int r,int w){ for(l+=mx-1,r+=mx+1;l^r^1;l>>=1,r>>=1){ if(~l&1)ae(l^1,w,1); if(r&1)ae(r^1,w,1); } } void ins2(int l,int r,int w){ for(l+=mx-1,r+=mx+1;l^r^1;l>>=1,r>>=1){ if(~l&1)ae(w,(l^1)+mx*2,1); if(r&1)ae(w,(r^1)+mx*2,1); } } std::deque<int>q; int main(){ fread(buf,1,sizeof(buf),stdin); n=_();m=_();k=_(); while(mx<n+1)mx<<=1; idp=mx*4+1; for(int i=mx-1;i;--i){ ae(i<<1,i,0),ae(i<<1^1,i,0); ae(mx*2+i,mx*2+(i<<1),0),ae(mx*2+i,mx*2+(i<<1^1),0); } for(int i=1;i<mx*2;++i)ae(i+mx*2,i,0); for(int i=0,a,b,c,d;i<m;++i){ a=_();b=_();c=_();d=_(); ++idp; ins1(a,b,idp); ins2(c,d,idp); ++idp; ins1(c,d,idp); ins2(a,b,idp); } memset(l,0x3f,sizeof(int)*(idp+2)); q.push_back(k+mx);l[k+mx]=0; while(!q.empty()){ int w=q.front();q.pop_front(); if(d[w])continue; d[w]=1; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(ev[i]){ if(l[u]>l[w]+1)l[u]=l[w]+1,q.push_back(u); }else{ if(l[u]>l[w])l[u]=l[w],q.push_front(u); } } } for(int i=1;i<=n;++i)printf("%d\n",l[i+mx]>>1); return 0; }