题目:

个点。个操作。
建权值的有向边;
建权值的有向边;
建权值的有向边;
问从点到其他点的最短路。无法到达输出


做法:

直接建图时间、空间复杂度都太大了。我们需要用线段树维护区间建图。开两棵线段树自底向上建零边,自顶向下建零边。如下图:
图片说明
当我们处理这种情况时,只需用线段树中的某些段点建边。处理时,就是线段树中某些段点和建边。至于直接建边。这样大大减少了边数。建完图后跑单源最短路。


代码:

#include <bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
typedef long long ll;
inline int read(void){
    char ch = getchar(); int ans = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) ans = ans*10 + ch-'0', ch = getchar();
    return ans;
}
const int N = 1e5 + 7;
const int M = 2e6 + 7;
const ll inf = 1e17;
int n, m, s, tag, T1[N<<2], T2[N<<2];
struct edge{
    int v, w, nxt;
}e[M];
int tot, head[N*10];
ll dis[N*10];
priority_queue<pair<ll,int> > q;
void addedge(int u, int v, int w){
    e[tot] = (edge){v, w, head[u]}; head[u] = tot++;
}
int build1(int l, int r, int rt){
    if (l == r){
        return T1[rt] = l;
    }
    T1[rt] = ++tag;
    int mid = (l+r) >> 1;
    int lid = build1(l, mid, lson); 
    int rid = build1(mid+1, r, rson);
    addedge(lid, T1[rt], 0);
    addedge(rid, T1[rt], 0);
    return T1[rt];
}
int build2(int l, int r, int rt){
    if (l == r){
        return T2[rt] = l;
    }
    T2[rt] = ++tag;
    int mid = (l+r) >> 1;
    int lid = build2(l, mid, lson); 
    int rid = build2(mid+1, r, rson);
    addedge(T2[rt], lid, 0);
    addedge(T2[rt], rid, 0);
    return T2[rt];
}
void upd_edge1(int v, int w, int L, int R, int l, int r, int rt){
    if (L <= l && r <= R){
        addedge(T1[rt], v, w); return;
    }
    int mid = (l+r) >> 1;
    if (L <= mid) upd_edge1(v, w, L, R, l, mid, lson);
    if (R > mid) upd_edge1(v, w, L, R, mid+1, r, rson);
}
void upd_edge2(int u, int w, int L, int R, int l, int r, int rt){
    if (L <= l && r <= R){
        addedge(u, T2[rt], w); return;
    }
    int mid = (l+r) >> 1;
    if (L <= mid) upd_edge2(u, w, L, R, l, mid, lson);
    if (R > mid) upd_edge2(u, w, L, R, mid+1, r, rson);
}
void init(void){
    tot = 0; memset(head, -1, sizeof head);
    tag = n;
    build1(1, n, 1); build2(1, n, 1);
}
void dijkstra(int s){
    fill(dis, dis+tag+1, inf);
    dis[s] = 0; q.push(make_pair(0, s));
    while (!q.empty()){
        int u = q.top().second;
        ll d = -q.top().first; q.pop();
        if (d != dis[u]) continue;
        for (int i = head[u]; i != -1; i = e[i].nxt){
            int v = e[i].v, w = e[i].w;
            if (dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                q.push(make_pair(-dis[v], v));
            }
        }
    }
}
int main(void){
    n = read(), m = read(), s = read();
    init();
    for (int i = 1; i <= m; ++i){
        int op, u, v, w, l, r;
        op = read();
        if (op == 1){
            u = read(), v = read(), w = read();
            addedge(u, v, w);
        }else if (op == 2){
            u = read(), l = read(), r = read(), w = read();
            upd_edge2(u, w, l, r, 1, n, 1);
        }else{
            v = read(), l = read(), r = read(), w = read();
            upd_edge1(v, w, l, r, 1, n, 1);
        }
    }
    dijkstra(s);
    for (int i = 1; i <= n; ++i){
        printf("%lld ", (dis[i] == inf ? -1 : dis[i]));
    }
    printf("\n");
    return 0;
}