bzoj3073: [Pa2011]Journeys

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
",l[i+mx]>>1);
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/6339933.html