CF786B Legacy

好久没有看到这样让人惊叹的建图方法了, 需要记录一下这个线段树优化建图的思路.
这位大佬 讲的已经很好了, 看他的就行.
其实这一题本质上就是用增加 \(logN\) 级别的点的代价将 \(O(N^2)\) 时间的建边优化到 \(O(NlogN)\) , 的确是线段树的思想.
开两颗线段树是防止冲突. 的确很妙.

#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 1e5 + 10;
inline int read(){
    char ch = getchar(); int x = 0;
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    return x;
}

int N, Q, S;

struct edge
{
    int to, cost;
};vector<edge> g[MAXN << 2];

namespace stree
{
    #define mid ((l + r) >> 1)

    struct Node
    {
        int ls, rs;
    }node[MAXN << 2];
    int rootin, rootout;

    int pos;

    void build(int &o, int l, int r, bool Type) {
        if(l == r) return o = l, void();
        o = ++pos;
        build(node[o].ls, l, mid, Type),
        build(node[o].rs, mid + 1, r, Type);
        if(Type) {
            g[o].push_back((edge) {node[o].ls, 0}),
            g[o].push_back((edge) {node[o].rs, 0});
        }
        else {
            g[node[o].ls].push_back((edge) {o, 0});
            g[node[o].rs].push_back((edge) {o, 0});
        }
    }

    void modify(int &o, int l, int r, int a, int b, int u, int c, bool Type) {
        if(l > b || r < a) return ;
        if(a <= l && r <= b) {
            if(Type) g[u].push_back((edge) {o, c});
            else g[o].push_back((edge) {u, c});
            return;
        }
        modify(node[o].ls, l, mid, a, b, u, c, Type);
        modify(node[o].rs, mid + 1, r, a, b, u, c, Type);
    }
    #undef mid
}

inline bool tension(const ll st, ll &lg) {
    return lg > st ? (lg = st, true) : false;
}

ll dis[MAXN << 2];
void dijkstra() {
    priority_queue<P, vector<P>, greater<P> > q;
    memset(dis, 0x3f, sizeof(dis));
    dis[S] = 0, q.push(P(0, S));

    while(!q.empty()) {
        P p = q.top(); q.pop();
        int u = p.second;
        if(dis[u] < p.first) continue;

        for(int i = 0; i < (int) g[u].size(); i++) {
            edge &e = g[u][i];
            if(tension(dis[u] + e.cost, dis[e.to]))
                q.push(P(dis[e.to], e.to));
        }
    }
}

int main(){
    cin>>N>>Q>>S;
    using namespace stree;
    pos = N; build(rootin, 1, N, true), build(rootout, 1, N, false);
    while(Q--) {
        int opt = read();
        if(opt == 1) {
            int u = read(), v = read(), c = read();
            g[u].push_back((edge) {v, c});
        }
        else if(opt == 2) {
            int u = read(), l = read(), r = read(), c = read();
            modify(rootin, 1, N, l, r, u, c, true);
        }
        else {
            int u = read(), l = read(), r = read(), c = read();
            modify(rootout, 1, N, l, r, u, c, false);
        }
    }
    dijkstra();
    for(int i = 1; i <= N; i++) 
        cout<<(dis[i] == INF ? -1 : dis[i])<<" ";
    return 0;
}

posted @ 2018-10-29 10:43  俺是小程  阅读(224)  评论(0编辑  收藏  举报