Codeforce 787 D. Legacy ( 线段树优化建图 + 最短路)

链接: D. Legacy

题意:
一眼看上去是求最短路,但他给出的边权是,一个点到一个区间的边权(也就是说 u 到 【l,r】内的点都有一条边)。
思路:
因为区间内的点都是连续的,所以我们可以用线段树把这些连续的点缩成几个区间,把区间变成一个新的点,再让这个新点于原来的点之间连上权值为 0 的边,这样可以很大的降低复杂度。
这个巨巨写得很详细 D. Legacy
代码:

#include <iostream>
#include <cstdio>
#include <map>
#include <math.h>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 4e6 + 7;
int head[maxn],num,n,q,s,id1[maxn],id2[maxn],ma=0,vis[maxn];
ll dis[maxn];
struct node{
    
    
    int to,next,w;
}e[maxn];
void add(int u,int v,int w){
    
    
     e[num].next=head[u];
     e[num].to=v;
     e[num].w=w;
     head[u]=num++;
}
priority_queue<pair<ll, ll> >  que ;
void dij(int s){
    
    
    for(int i = 0; i <= 2*ma; i++){
    
    
        dis[i]=1e18;
    }
    memset(vis,0,sizeof(vis));
    dis[s]=0;
    que.push(make_pair(0,s));
    while(que.size())
    {
    
    
        int u=que.top().second;que.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
    
    
            int v=e[i].to;
            ll w=e[i].w;
            if(dis[v]>dis[u]+w)
            {
    
    
                dis[v]=dis[u]+w;
                que.push(make_pair(-dis[v],v));
            }
        }
    }
}
void build1(int l,int r,int rt){
    
    
     if(l == r){
    
    
        id1[l] = rt ;
        ma=max(ma,rt);
        return ;
     }
     int mid = (l + r) / 2;
     add(rt,rt<<1,0);
     add(rt,rt<<1|1,0);
     build1(l,mid,rt<<1);
     build1(mid+1,r,rt<<1|1);
}
void build2(int l,int r,int rt){
    
    
     if(l == r){
    
    
        id2[l] = rt+ma;
        return ;
     }
     int mid = (l + r) / 2;
     add((rt<<1)+ma,rt+ma,0);
     add((rt<<1|1)+ma,rt+ma,0);
     build2(l,mid,rt<<1);
     build2(mid+1,r,rt<<1|1);
}
void update1(int L,int R,int idd,int w,int l,int r,int rt){
    
    
     if(L <= l && R >= r){
    
    
        add(idd,rt,w);
        return ;
     }
     int mid=(l+r)/2;
     if(L <= mid) update1(L,R,idd,w,l,mid,rt<<1);
     if(R > mid) update1(L,R,idd,w,mid+1,r,rt<<1|1);
}
void update2(int L,int R,int idd,int w,int l,int r,int rt){
    
    
     if(L <= l && R >= r){
    
    
        add(rt+ma,idd,w);
        return ;
     }
     int mid=(l+r)/2;
     if(L <= mid) update2(L,R,idd,w,l,mid,rt<<1);
     if(R > mid) update2(L,R,idd,w,mid+1,r,rt<<1|1);
}
int main(){
    
    
    scanf("%d%d%d",&n,&q,&s);
    memset(head,-1,sizeof(head));
    build1(1,n,1);
    build2(n+1,2*n,1);
    int op,w,v,u,l,r;
    while(q--){
    
    
         scanf("%d",&op);
         if(op==1){
    
    
            scanf("%d%d%d",&v,&u,&w);
            add(id2[v + n],id1[u],w);
         }
         if(op==2){
    
    
            scanf("%d%d%d%d",&v,&l,&r,&w);
            update1(l,r,id2[v+n],w,1,n,1);
         }
         if(op==3){
    
    
            scanf("%d%d%d%d",&v,&l,&r,&w);
            update2(l+n,r+n,id1[v],w,n+1,2*n,1);
         }
    }
    for(int i = 1; i <= n; i++){
    
    
        add(id1[i],id2[i+n],0);
        add(id2[i+n],id1[i],0);
    }
    dij(id2[s+n]);
    for(int i = 1; i <= n; i++){
    
    
       if(dis[id1[i]]>=1e18) printf ("-1 ");
       else  printf ("%lld ",dis[id1[i]]);
    }
    printf ("\n");

}

猜你喜欢

转载自blog.csdn.net/hddddh/article/details/107667977
今日推荐