[CF#786B]Legacy:线段树优化连边+Dijkstra

分析:

线段树优化连边模板题,一开始琢磨了半天能不能只用一颗线段树,好像不太现实......
贴一下学长课件上的题解:

线段树优化建图。
建立两棵线段树,其上点的点权分别表示“到达这个区间内所有点的最小花费”和“到达这个区间内任意一个点的最小花费”。
对于第一种路直接加边即可
对于第二种路,添加从v到第一棵线段树对应区间中的点的边
对于第三种路,添加从第二棵线段树对应区间中的点到v的边

然后直接跑堆优化Dijkstra即可。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
const int MAXN=100005;
inline LL read(){
    LL 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<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
int n,q,s,ecnt,head[MAXN<<4],pos[MAXN],ver,ql,qr;
LL dis[MAXN<<4],k;
bool vis[MAXN<<4];
struct Edge{
    int to,nxt;LL w;
}e[MAXN*26];
struct Pair{
    int pos;LL dis;
    friend bool operator < (Pair x,Pair y){
        return x.dis<y.dis;
    }
    friend bool operator > (Pair x,Pair y){
        return x.dis>y.dis;
    }
};
inline Pair Mp(int x,LL y){
    Pair ret;ret.pos=x,ret.dis=y;return ret;
}
inline void add_edge(int bg,int ed,LL val){
    ecnt++;
    e[ecnt].to=ed;
    e[ecnt].nxt=head[bg];
    e[ecnt].w=val;
    head[bg]=ecnt;
}
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
void build(int o,int l,int r){
    if(l==r){
        pos[l]=o;
        return;
    }
    add_edge(o,lc,0);
    add_edge(o,rc,0);
    add_edge(mid-l+1==1?lc:lc+(n<<2),o+(n<<2),0);
    add_edge(r-mid==1?rc:rc+(n<<2),o+(n<<2),0);
    build(lc,l,mid);
    build(rc,mid+1,r);
}
void upd(int o,int l,int r,int typ){
    if(ql<=l&&r<=qr){
        if(typ==2) add_edge(pos[ver],o,k);
        else add_edge(l==r?o:o+(n<<2),pos[ver],k);
        return;
    }
    if(mid>=ql) upd(lc,l,mid,typ);
    if(mid<qr) upd(rc,mid+1,r,typ);
}
priority_queue<Pair,vector<Pair>,greater<Pair> > pq;
inline void dijkstra(){
    memset(dis,0x3f,sizeof dis);
    while(!pq.empty()) pq.pop();
    pq.push(Mp(pos[s],0));
    while(!pq.empty()){
        int now=pq.top().pos;LL len=pq.top().dis;pq.pop();
        if(vis[now]) continue;
        vis[now]=1;
        dis[now]=len;
        for(register int i=head[now];i;i=e[i].nxt){
            int ver=e[i].to;
            if(!vis[ver]&&dis[ver]>dis[now]+e[i].w){
                dis[ver]=dis[now]+e[i].w;
                pq.push(Mp(ver,dis[ver]));
            }
        }
    }
}
int main(){
    n=read(),q=read(),s=read();
    build(1,1,n);
    for(int i=1;i<=q;i++){
        int opt=read();
        if(opt==1){
            int u=read(),v=read();k=read();
            add_edge(pos[u],pos[v],k);
        }
        else if(opt==2){
            ver=read(),ql=read(),qr=read(),k=read();
            upd(1,1,n,2);
        }
        else{
            ver=read(),ql=read(),qr=read(),k=read();
            upd(1,1,n,3);
        }
    }
    dijkstra();
    for(int i=1;i<=n;i++){
        if(dis[pos[i]]>1e18) printf("-1 ");
        else printf("%I64d ",dis[pos[i]]);
    }
    printf("\n");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9489656.html