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