\(Descriptioin\):
一个 \(w \times h \ (1 \leq w, h \leq n)\) 的网格上有 \(n \ (1 \leq n \leq 7 \times 10 ^ 4)\) 个整点;
有 \(m \ (m \leq 1.5 \times 10 ^ 5)\) 次连边,每次连边长度为 \(t_i \ (1 \leq t_i \leq 10^4)\),以第 \(p_i\) 个整点为起点向坐标满足 \(l_i \leq x \leq r_i, \ d_i \leq y \leq u_i\) 的所有点连边。
求 \(1\) 号点为起点的单元最短路。
\(Sol\):
因为没有负权边,所以可以用到 \(dijkstra\) 的一个性质:以点 \(u\) 为起点松弛操作之后,到 \(u\) 的最短路就不会该边了。
可以用数据结构来维护矩阵上的点,最短路时不必把边建出来,只需每次找到一个最短路最小的矩阵,并以该矩阵中未被删除的点为起点进行松弛,并把这些点删除即可。
数据结构的选择很多,我写了线段树套 \(set\)。
时间复杂度 \(O(n\log_2^2n)\),空间复杂度 \(O(n \log_2 n)\)。
\(Source\):
#include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <vector> #include <queue> int in() { int x = 0; char c = getchar(); bool f = 0; while (c < '0' || c > '9') f |= c == '-', c = getchar(); while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return f ? -x : x; } template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; } template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; } const int N = 7e4 + 5; struct city { int x, y; } a[N]; struct edge { int p, t, l, r, d, u; } b[N * 3]; int n, m, w, h; int dis[N]; bool vis[N * 3]; std::vector<int> s[N]; typedef std::pair<int, int> pii; std::priority_queue<pii> q; std::queue<int> tmp; struct segment_tree { std::set<pii> t[N << 2]; void insert(int id_a, int tl = 1, int tr = w, int p = 1) { t[p].insert(pii(a[id_a].y, id_a)); if (tl == tr) return ; int mid = (tl + tr) >> 1; if (mid >= a[id_a].x) insert(id_a, tl, mid, p << 1); else insert(id_a, mid + 1, tr, p << 1 | 1); } void remove(int id_a, int tl = 1, int tr = w, int p = 1) { t[p].erase(pii(a[id_a].y, id_a)); if (tl == tr) return ; int mid = (tl + tr) >> 1; if (mid >= a[id_a].x) remove(id_a, tl, mid, p << 1); else remove(id_a, mid + 1, tr, p << 1 | 1); } void modify(int d, int id_b, int tl = 1, int tr = w, int p = 1) { if (b[id_b].l <= tl && tr <= b[id_b].r) { std::set<pii>::iterator x = std::lower_bound(t[p].begin(), t[p].end(), pii(b[id_b].d, 0)); for (; x != t[p].end() && x->first <= b[id_b].u; ++x) { dis[x->second] = d; for (unsigned i = 0; i < s[x->second].size(); ++i) if (!vis[s[x->second][i]]) q.push(pii(-d - b[s[x->second][i]].t, s[x->second][i])); tmp.push(x->second); } for (; !tmp.empty(); remove(tmp.front()), tmp.pop()); return ; } int mid = (tl + tr) >> 1; if (mid >= b[id_b].l) modify(d, id_b, tl, mid, p << 1); if (mid < b[id_b].r) modify(d, id_b, mid + 1, tr, p << 1 | 1); } } T; int main() { //freopen("in", "r", stdin); n = in(), m = in(), w = in(), h = in(); for (int i = 1; i <= n; ++i) a[i] = (city){in(), in()}; for (int i = 1; i <= m; ++i) { b[i] = (edge){in(), in(), in(), in(), in(), in()}; s[b[i].p].push_back(i); } for (int i = 2; i <= n; ++i) T.insert(i); for (unsigned i = 0; i < s[1].size(); ++i) q.push(pii(-b[s[1][i]].t, s[1][i])); while (!q.empty()) { int d = q.top().first, u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; T.modify(-d, u); } for (int i = 2; i <= n; ++i) printf("%d\n", dis[i]); return 0; }