[补档计划] 树4 - 线段树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[补档计划] 树4 - 线段树相关的知识,希望对你有一定的参考价值。

[CF787D] Legacy

题意

  $N$ 个点, $M$ 条连边操作:

    $1~u~v~w~:~u\rightarrow v$ .

    $2~u~l~r~w~:~u\rightarrow [l, r]$

    $3~u~l~r~w~:~[l, r]\rightarrow u$ .

  给定点 $s$ , 求单源最短路.

  $N\le 10^5$ .

分析

  考虑使用 线段树结构 优化 建图.

  建立一棵线段树, 每个点表示一个区间.

  拆点, 线段树的每个点拆成 入点 和 出点 .

  出线段树 的儿子连父亲, 因为可以通过父亲出去.

  入线段树 的父亲连儿子, 因为可以通过父亲进来.

  对应 入节点 连 出节点 .

  对于一次连边操作, 将 出线段树 对应节点连到 入线段树.

实现

技术分享
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <queue>
using namespace std;

#define F(i, a, b) for (register int i = (a); i <= (b); i++)
#define fore(k, x) for (register int k = hd[x]; k > 0; k = mp[k].nx)

#define LL long long

const int S = 600000;
const LL INF = (LL)1e16;

int n, q, s;

int m;
struct Edge {
    int v, d, nx;
    inline Edge(int _v = 0, int _d = 0, int _nx = 0): v(_v), d(_d), nx(_nx) {}
}mp[2500000];
int tot, hd[S];

LL dis[S];
priority_queue< pair<LL, int> > que;

inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
}

inline int id(int k, int x) { return k * ( (1<<m)+(1<<m)-1 ) + x; }
inline void Ins(int u, int v, int d = 0) { mp[++tot] = Edge(v, d, hd[u]); hd[u] = tot; }
void Prework(int x, int L, int R) {
    if (R < 1 || L > n) return;
    Ins(id(1, x), id(0, x));
    if (L == R) return;
    Ins(id(0, x<<1), id(0, x));
    Ins(id(0, x<<1|1), id(0, x));
    Ins(id(1, x), id(1, x<<1));
    Ins(id(1, x), id(1, x<<1|1));
    int M = (L+R) >> 1;
    Prework(x<<1, L, M);
    Prework(x<<1|1, M+1, R);
}
inline void Add(int u, int L, int R, int w, int kd) {
    // kd = 2 : u -> [L, R]
    // kd = 3 : [L, R] -> u
    for (L--, R++, L += (1<<m), R += (1<<m), u += (1<<m); L^R^1; L >>= 1, R >>= 1) {
        if (!(L&1)) 
            kd == 2 ? Ins(id(0, u), id(1, L^1), w) : Ins(id(0, L^1), id(1, u), w);
        if (R&1)
            kd == 2 ? Ins(id(0, u), id(1, R^1), w) : Ins(id(0, R^1), id(1, u), w);
    }
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("CF787D.in", "r", stdin);
        freopen("CF787D.out", "w", stdout);
    #endif

    n = rd(), q = rd(), s = rd();

    m = 0;
    while ((1<<m)-1 < n+1)
        m++;
    Prework(1, 0, (1<<m)-1);
    F(i, 1, q) {
        int t = rd();
        if (t == 1) {
            int u = rd(), v = rd(), w = rd();
            Ins(id(0, u+(1<<m)), id(1, v+(1<<m)), w);
        }
        else {
            int u = rd(), l = rd(), r = rd(), w = rd();
            Add(u, l, r, w, t);
        }
    }

    F(i, 1, 2 * ( (1 << m) + (1 << m) + 1 )) dis[i] = INF;
    que.push(make_pair(0, id(1, s+(1<<m))));
    while (!que.empty()) {
        pair<LL, int> x = que.top(); que.pop();
        if (dis[x.second] != INF) continue;
        dis[x.second] = -x.first;
        fore(k, x.second)
            if (dis[mp[k].v] == INF)
                que.push(make_pair(x.first - mp[k].d, mp[k].v));
    }
    F(i, 1, n) printf("%I64d ", dis[id(1, i+(1<<m))] != INF ? dis[id(1, i+(1<<m))] : -1); printf("\n");

    return 0;
}
View Code

 

以上是关于[补档计划] 树4 - 线段树的主要内容,如果未能解决你的问题,请参考以下文章

[补档计划] 树6 - 莫队算法

[补档题解]后缀树节点数

[补档][Tvyj 1729]文艺平衡树

POJ训练计划2528_Mayor&#39;s posters(线段树/成段更新+离散化)

[补档][Tyvj 1728]普通平衡树

线段树详解