[bzoj3073]Journeys

来源:互联网 发布:infographic制作软件 编辑:程序博客网 时间:2024/06/06 02:02

题目描述

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号国家能到任意一个国家。

注意:可能有重边

线段树优化

我们朴素想法是把图建出来跑最短路。
直接建图边数爆炸。
尝试数据结构优化连边。
可以建两颗线段树,分别称为A和B。
A和B中同一个节点B向A连边权为0。
A中儿子向父亲连边权为0。
B中父亲向儿子连边权为0。
对于一条边,可以分别在两颗线段树定位对应区间。
建一个新的辅助点,A中都向它连边权为1,它向B中连边权为1。
这样的话,原图联通性没有改变,而且新图上p在A上的叶子走到每个点在A上的叶子的最短路除以2就是原图最短路。
建完图跑Dij+heap

#include<cstdio>#include<algorithm>#include<queue>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=500000+10,maxtot=5*maxn+10,maxm=maxtot*7,inf=1000000000;struct dong{    int x,y;    friend bool operator<(dong a,dong b){        return a.y>b.y||a.y==b.y&&a.x<b.x;    }} zlt;priority_queue<dong> dl;int h[maxtot],go[maxm],dis[maxm],next[maxm],left[maxtot],right[maxtot],f[maxtot],leaf[maxn],sta[80];bool bz[maxtot];int i,j,k,l,r,t,n,m,p,now,tot,top,root1,root2;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9'){        if (ch=='-') f=-1;        ch=getchar();    }    while (ch>='0'&&ch<='9'){        x=x*10+ch-'0';        ch=getchar();    }    return x*f;}void add(int x,int y,int z){    go[++top]=y;    dis[top]=z;    next[top]=h[x];    h[x]=top;}void build(int &x,int l,int r,int p){    x=++tot;    if (l==r){        if (p==1) leaf[l]=x;        return;    }    int mid=(l+r)/2;    build(left[x],l,mid,p);build(right[x],mid+1,r,p);    if (p==1){        add(left[x],x,0);        add(right[x],x,0);    }    else{        add(x,left[x],0);        add(x,right[x],0);    }}void connect(int x,int y,int l,int r){    add(y,x,0);    if (l==r) return;    int mid=(l+r)/2;    connect(left[x],left[y],l,mid);    connect(right[x],right[y],mid+1,r);}void link(int x,int l,int r,int a,int b,int p){    if (l==a&&r==b){        if (p==1) add(x,tot,1);else add(tot,x,1);        return;    }    int mid=(l+r)/2;    if (b<=mid) link(left[x],l,mid,a,b,p);    else if (a>mid) link(right[x],mid+1,r,a,b,p);    else{        link(left[x],l,mid,a,mid,p);        link(right[x],mid+1,r,mid+1,b,p);    }}void write(int x){    if (!x){        putchar('0');        putchar('\n');        return;    }    top=0;    while (x){        sta[++top]=x%10;        x/=10;    }    while (top) putchar('0'+sta[top--]);    putchar('\n');}int main(){    //freopen("data.in","r",stdin);    n=read();m=read();p=read();    build(root1,1,n,1);build(root2,1,n,-1);    connect(root1,root2,1,n);    fo(i,1,m){        j=read();k=read();l=read();r=read();        ++tot;        link(root1,1,n,j,k,1);link(root2,1,n,l,r,-1);        swap(j,l);swap(k,r);        ++tot;        link(root1,1,n,j,k,1);link(root2,1,n,l,r,-1);    }    t=leaf[p];    f[t]=0;    zlt.x=t;zlt.y=0;    dl.push(zlt);    fo(i,1,tot)        if (i!=t){            zlt.x=i;zlt.y=f[i]=inf;            dl.push(zlt);        }    fo(i,1,tot-1){        do{             zlt=dl.top();            dl.pop();            now=zlt.x;        }while (bz[now]);        bz[now]=1;        t=h[now];        while (t){            if (f[now]+dis[t]<f[go[t]]){                f[go[t]]=f[now]+dis[t];                zlt.x=go[t];zlt.y=f[go[t]];                dl.push(zlt);            }            t=next[t];        }    }    fo(i,1,n) write(f[leaf[i]]/2);}
0 0
原创粉丝点击