• 线段树优化建图 && CF-786B.Legacy(优化建图,dijkstra)


    洛谷传送门


    线段树优化建图

    用两个线段树A和B,一个我们称之为入树,一个我们称之为出树,对于每一条边,都是从入树连向出树,具体如下:

    1. 若是两个点之间连边,直接从入树对应的叶子节点连向出树的叶子节点
    2. 若为单点连向区间,则入树的叶子节点连向出树的区间(按照线段树的插入)
    3. 若为区间连向单点,同理,入树的区间连向出树的叶子节点

    然后就可以在线段树上做各种图论算法了(把两个线段树看做图即可)。

    解题思路

    很显然是个板子,线段树优化完建图后,直接跑最短路即可。

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<set>
    using namespace std;
    const int maxn=400005;
    const long long maxx=10000000000005;
    int n,m,s,qaq=400001,p[maxn*2],cnt;
    long long dis[maxn*2];
    set<pair<long long,int> > q;
    struct node{
        int v,next,w;
    }e[maxn*5];
    int find(int x){
        int l=1,r=n,id=1;
        while(l!=r){
            int mid=(l+r)/2;
            if(x<=mid) r=mid,id=id*2;
            else l=mid+1,id=id*2+1;
        }
        return id;
    }
    void insert(int u,int v,int w){
        cnt++;
        e[cnt].v=v;
        e[cnt].next=p[u];
        e[cnt].w=w;
        p[u]=cnt;
    }
    void update(int k,int id,int l,int r,int x,int y,int z,int w){
        if(l>=x&&r<=y){
            if(k==1) insert(z,qaq+id,w);
            if(k==2) insert(id,z,w);
            if(k==3) insert(z,qaq+id,w);
            return;
        }
        int mid=(l+r)/2;
        if(x<=mid) update(k,id*2,l,mid,x,y,z,w);
        if(y>mid) update(k,id*2+1,mid+1,r,x,y,z,w);
    }
    void add(int ux,int uy,int vx,int vy,int w){
        if(vx!=vy){
            int u=find(ux);
            update(1,1,1,n,vx,vy,u,w); 
            return;
        }
        if(ux!=uy){
            int v=find(vx);
            update(2,1,1,n,ux,uy,qaq+v,w); 
            return;
        }
        int u=find(ux);
        update(3,1,1,n,vx,vx,u,w);
    }
    void init(int id,int l,int r){
        if(l==r){
            insert(qaq+id,id,0);
            return;
        }
        int mid=(l+r)/2;
        insert(id*2,id,0);
        insert(id*2+1,id,0);
        insert(qaq+id,qaq+id*2,0); 
        insert(qaq+id,qaq+id*2+1,0);
        init(id*2,l,mid);
        init(id*2+1,mid+1,r);
    }
    int main(){
        memset(p,-1,sizeof(p));
        cin>>n>>m>>s;
        for(int i=1;i<maxn*2;i++) dis[i]=maxx;
        init(1,1,n);
        for(int i=1;i<=m;i++){
            int t;
            scanf("%d",&t);
            if(t==1){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                add(u,u,v,v,w);
            }else {
                if(t==2){
                    int u,l,r,w;
                    scanf("%d%d%d%d",&u,&l,&r,&w);
                    add(u,u,l,r,w);
                }else{
                    int l,r,v,w;
                    scanf("%d%d%d%d",&v,&l,&r,&w);
                    add(l,r,v,v,w);
                }
            }
        }
        int f=find(s);
        dis[f]=0;
        q.insert(make_pair(0,f));
        while(!q.empty()){
            int u=q.begin()->second;
            q.erase(q.begin());
            for(int i=p[u];i!=-1;i=e[i].next){
                int v=e[i].v;
                if(dis[v]>dis[u]+e[i].w){
                    q.erase(make_pair(dis[v],v));
                    dis[v]=dis[u]+e[i].w;
                    q.insert(make_pair(dis[v],v));
                }
            }
        }
        for(int i=1;i<=n;i++) {
            int ff=find(i);
            cout<<((dis[ff]!=maxx)?dis[ff]:-1)<<" ";
        }
        return 0;
    }
  • 相关阅读:
    网络流24题之圆桌问题
    BZOJ 4276: [ONTAK2015]Bajtman i Okrągły Robin
    网络流24题航空路线问题
    BZOJ1038 瞭望塔
    BZOJ4029 HEOI2015定价
    BZOJ1226 SDOI2009学校食堂
    网络流24题之魔术球问题
    网络流24题之最小路径覆盖问题
    【BZOJ1098】[POI2007]办公楼biu
    BZOJ3065 带插入区间K小值
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/14723434.html
Copyright © 2020-2023  润新知