Legacy

洛谷-CF786B-Legacyopen in new window

分析

线段树优化建图。

实现

#include <iostream>
#include <cstring>
#include <queue>
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;

typedef long long LL;
const int N = 800010, M = 2000010;
struct edge {
    int to, next, w;
};
edge e[M];
int idx, head[N];
int n, m, s;
struct node {
    int ls, rs;
    #define ls(x) t[x].ls
    #define rs(x) t[x].rs
};
int tot, root[3];
node t[N];
LL dis[N];
bool mark[N];

void add_edge (int u, int v, int w) {
    e[idx].w = w;
    e[idx].to = v;
    e[idx].next = head[u];
    head[u] = idx ++;
}
int build1 (int l, int r) {
    if (l == r) return l; // 1 ~ n

    int cur = ++ tot;
    int mid = l + r >> 1;
    ls(cur) = build1(l, mid);
    rs(cur) = build1(mid + 1, r);
    // 父 -> 子
    add_edge(cur, ls(cur), 0);
    add_edge(cur, rs(cur), 0);
    return cur;
}
// u -> [a, b]
void modify1 (int rt, int l, int r, int u, int a, int b, int w) {
    if (a <= l && r <= b) {
        add_edge(u, rt, w);
        return;
    }

    int mid = l + r >> 1;
    if (a <= mid) modify1(ls(rt), l, mid, u, a, b, w);
    if (b >= mid + 1) modify1(rs(rt), mid + 1, r, u, a, b, w);
}
int build2 (int l, int r) {
    if (l == r) return l; // 1 ~ n

    int cur = ++ tot;
    int mid = l + r >> 1;
    ls(cur) = build2(l, mid);
    rs(cur) = build2(mid + 1, r);
    // 子 -> 父
    add_edge(ls(cur), cur, 0);
    add_edge(rs(cur), cur, 0);
    return cur;
}
// [a, b] -> v
void modify2 (int rt, int l, int r, int a, int b, int v, int w) {
    if (a <= l && r <= b) {
        add_edge(rt, v, w);
        return;
    }

    int mid = l + r >> 1;
    if (a <= mid) modify2(ls(rt), l, mid, a, b, v, w);
    if (b >= mid + 1) modify2(rs(rt), mid + 1, r, a, b, v, w);
}
void spfa (int s) {
    memset(dis, 0x3f, sizeof(dis));

    queue<int> q;
    dis[s] = 0;
    q.push(s);
    mark[s] = true;
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        mark[cur] = false;
        for (int i = head[cur]; i != -1; i = e[i].next) {
            int to = e[i].to, w = e[i].w;
            if (dis[cur] + w < dis[to]) {
                dis[to] = dis[cur] + w;
                if (mark[to] == false) {
                    q.push(to);
                    mark[to] = true;
                }
            }
        }
    }
}

int main () {
    memset(head, -1, sizeof(head));
    cin >> n >> m >> s;

    tot = n; // 线段树结点的编号从 n + 1 开始
    root[1] = build1(1, n);
    root[2] = build2(1, n);
    for (int i = 1, opt; i <= m; ++ i) {
        cin >> opt;
        if (opt == 1) { // 点 -> 点
            int u, v, w;
            cin >> u >> v >> w;
            add_edge(u, v, w);
        } else if (opt == 2) { // 点 -> 区间
            int u, l, r, w;
            cin >> u >> l >> r >> w;
            modify1(root[1], 1, n, u, l, r, w);
        } else { // 区间 -> 点
            int v, l, r, w;
            cin >> v >> l >> r >> w;
            modify2(root[2], 1, n, l, r, v, w);
        }
    }
    spfa(s);
    for (int i = 1; i <= n; ++ i)
        cout << (dis[i] == inf ? -1 : dis[i]) << ' ';
    return 0;
}
最后修改于: