CodeForces---787D:Legacy【线段树优化建图+最短路】

题目:

戳这里啊~~~

题意:

给你三种操作:(1)点到点建边;(2)点到区间建边;(3)区间到点建边;最后求起点到其他点的最短距离

分析:

最短距离无非建边跑Dijkstra即可,考虑如何对区间建边,如果直接对区间的每一点建边,那N^2的复杂度是行不通的,考虑将区间映射到线段树上的一个点:

(1)建两颗线段树,一颗表示出度的点,一颗表示入度的点

(2)对于表示出度的树,对每一节点和它父亲节点连一条长度为0的单向边(如果能从父亲出发,那么儿子也一定能);对于表示入度的树,对每一节点和它的儿子节点连一条长度为0的单向边(如果能到达父亲,那么也一定能达到儿子),并将其叶子节点和第一颗树对应的节点连一条长度为0的单向边(相当于从到达的点又出发),完全可以只建一颗树,但这样会走很多无用的边

(3)为了能区别两颗树,就必须给两颗树从新编号,建边时,直接找到对应的编号建边即可

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int maxn = 2e5+15;
const LL inf = 1e18;
inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
    return x * f;
}
inline void write(LL x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
int n,q,s,t,l,r,w,p,u,v,tot;
int head[maxn<<3],cnt,tra[maxn<<3],trb[maxn<<3],in[maxn],out[maxn];
struct edge{
    int to,nxt,w;
}e[maxn<<4];
inline void add(int u,int v,int _w){
    e[++cnt].to = v;e[cnt].w = _w;
    e[cnt].nxt = head[u];head[u] = cnt;
}
void build(int l,int r,int x){
    tra[x]=++tot; trb[x]=++tot;
     if(l == r){
         out[l] = trb[x];in[l] = tra[x];
         add(trb[x],tra[x],0); 
         return ;
     }
     int mid = (l+r) >> 1;
     build(l,mid,x<<1);
     build(mid+1,r,x<<1|1);
     add(tra[x<<1],tra[x],0);
     add(tra[x<<1|1],tra[x],0);
     add(trb[x],trb[x<<1],0);
     add(trb[x],trb[x<<1|1],0);
}
void Updata(int l,int r,int L,int R,int x,int v,int w,int op){
    if(l > R || r < L) return ;
    if(l >= L && r <= R){
        if(op == 2) add(in[v],trb[x],w);
        else add(tra[x],out[v],w);
        return;
    }
    int mid = (l+r) >> 1;
    Updata(l,mid,L,R,x<<1,v,w,op);
    Updata(mid+1,r,L,R,x<<1|1,v,w,op);
}
LL dis[maxn<<3];
struct node{
    int x; LL len;
    friend bool operator <(node a,node b){
        return a.len > b.len;
    }
};
void diskstra(){
    for(int i = 0;i <= tot; ++i) dis[i] = inf;
    dis[in[s]] = dis[out[s]] = 0;
    priority_queue<node> q;
    q.push(node{in[s],0LL});
    while(!q.empty()){
         node now = q.top();q.pop();
         if(now.len > dis[now.x]) continue;
         for(int i = head[now.x]; i ; i = e[i].nxt){
            int v = e[i].to;
            if(dis[v] > dis[now.x] + e[i].w){
                dis[v] = dis[now.x] + e[i].w;
                q.push(node{v,dis[v]});
            }
         }
    }
}
int main(){
    n = read(),q =read(),s = read();
    build(1,n,1);
    while(q--){
        t = read();
        if(t == 1){
           u = read(),v = read(),w = read();
           add(in[u],out[v],w);
        }
        else{
            v = read(),l = read(),r = read(),w = read();
            Updata(1,n,l,r,1,v,w,t);
        }
    }
    diskstra();
    for(int i = 1;i <= n; ++i){
        if(dis[out[i]] == inf) printf("-1 ");
        else write(dis[out[i]]),putchar(' ');
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41157137/article/details/92250457
今日推荐