BZOJ3073:Journeys(线段树)

传送门

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

题解:线段树优化构图。
区间连边直接在线段树上连就好了。连边时新建点就不用 log2n ,可以做到 logn

#include
using namespace std;
inline int read(){
    char ch=getchar();int i=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
    return i*f;
} 
inline void W(int x){
    static int buf[50];
    if(!x){putchar('0');return;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10;x/=10;}
    while(buf[0]){putchar(buf[buf[0]--]+'0');}
}
const int Maxn=5e5+50;
int n,m,s,posIn[Maxn<<2],posOut[Maxn<<2],dis[Maxn<<3],tot,tot2,vis[Maxn<<3],pos[Maxn];
struct E{
    E *nxt;
    int to,val;
    E():nxt(NULL){}
}Pool[Maxn*18],*pool=Pool,*edge[Maxn<<3];
inline void push_back(E *&t,int to,int val){
    ++pool;
    pool->to=to;
    pool->nxt=t;
    pool->val=val;
    t=pool;
}
inline void build(int k,int l,int r){
    (tot2?posIn[k]=++tot:posOut[k]=++tot);
    if(k!=1){
        if(tot2){
            push_back(edge[posIn[k>>1]],posIn[k],0);
        }else{
            push_back(edge[posOut[k]],posOut[k>>1],0);
        }
    }
    if(l==r){
        if(tot2)push_back(edge[posIn[k]],posOut[k],0),pos[l]=posIn[k];
        return;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline void findpos(int k,int l,int r,int L,int R,int t){
    if(L<=l&&r<=R){
        if(t)push_back(edge[posOut[k]],tot,1);
        else push_back(edge[tot],posIn[k],0);
        return;
    }
    int mid=(l+r)>>1;
    if(R<=mid)findpos(k<<1,l,mid,L,R,t);
    else if(L>mid)findpos(k<<1|1,mid+1,r,L,R,t);
    else findpos(k<<1,l,mid,L,R,t),findpos(k<<1|1,mid+1,r,L,R,t);
}
typedef pair<int,int> pii;
priority_queue< pii,vector,greater >q;
inline void dijkstra(int S){
    memset(dis,0x3f,sizeof(dis));
    dis[S]=0;q.push(make_pair(0,S));
    while(!q.empty()){
        if(vis[q.top().second]){q.pop();continue;}
        pii t=q.top();q.top();vis[t.second]=1;
        for(E *e=edge[t.second];e;e=e->nxt){
            if(dis[e->to]>dis[t.second]+e->val){
                dis[e->to]=dis[t.second]+e->val;
                q.push(make_pair(dis[e->to],e->to));
            }
        }
    }
}
inline void getans(int k,int l,int r){
    if(l==r){
        W(dis[posOut[k]]);putchar('\n');
        return;
    }
    int mid=(l+r)>>1;
    getans(k<<1,l,mid);
    getans(k<<1|1,mid+1,r);
}
int main(){
    n=read(),m=read(),s=read();
    build(1,1,n);
    tot2=tot;
    build(1,1,n);
    for(int i=1;i<=m;i++){
        int L1=read(),R1=read(),L2=read(),R2=read();
        ++tot;
        findpos(1,1,n,L1,R1,1);
        findpos(1,1,n,L2,R2,0);
        ++tot;
        findpos(1,1,n,L2,R2,1);
        findpos(1,1,n,L1,R1,0);
    }
    dijkstra(pos[s]);
    getans(1,1,n);
}

你可能感兴趣的:(线段树)