1. 程式人生 > >[補檔計劃] 樹4 - 線段樹

[補檔計劃] 樹4 - 線段樹

pre gist sdi spl air add second int lap

[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 - 線段樹