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

Sample Output

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);
    }
}

 

posted @ 2018-06-20 09:16  fcwww  阅读(228)  评论(0编辑  收藏  举报