线段树优化建图 && 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;
}

 

posted @ 2021-04-30 21:46  尹昱钦  阅读(43)  评论(0编辑  收藏  举报