Wannafly挑战赛2 D.Delete(拓扑排序 + dij预处理 + 线段树维护最小值)
题目链接 D.Delete
考虑到原图是个DAG,于是我们可以求出每个点的拓扑序。
然后预处理出起点到每个点的最短路$ds[u]$,
和所有边反向之后从终点出发到每个点的最短路$dt[u]$。
令点$u$的拓扑序为$a(u)$。
对于特定的一条边$(u, v, w)$,相当于给所有拓扑序为$[a(u) + 1, a[v] - 1]$的点贡献了一条总长度为$ds[u] + dt[v] + w$的路径。
我们在询问点$u$的时候找到对$u$点贡献的所有路径中长度最小的即可。
特别地,当$s$无法到达$u$或$u$无法到达t时,输出原图从$s$到$t$的最短路即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R typedef long long LL; const int N = 1e5 + 10; const LL INF = 1e18; int n, m, s, t, q; LL ans; LL ds[N], dt[N]; LL mi[N << 2]; struct node{ int u; LL w; friend bool operator < (const node &a, const node &b){ return a.w > b.w; } }; vector <node> v[N], g[N]; int a[N], deg[N]; void dij(int s, LL dis[], vector <node> v[]){ priority_queue <node> q; static bool vis[N]; rep(i, 1, n) dis[i] = 1e18, vis[i] = false; q.push({s, 0}); dis[s] = 0; while (!q.empty()){ int u = q.top().u; q.pop(); if (vis[u]) continue; vis[u] = 1; for (auto edge : v[u]) if (dis[u] + edge.w < dis[edge.u]){ dis[edge.u] = dis[u] + edge.w; q.push({edge.u, dis[edge.u]}); } } } void getdag(){ queue <int> q; int cnt = 0; rep(i, 1, n){ if (deg[i] == 0) a[i] = ++cnt, q.push(i); } while (!q.empty()){ int x = q.front(); q.pop(); for (auto edge : v[x]){ --deg[edge.u]; if (deg[edge.u] == 0) a[edge.u] = ++cnt, q.push(edge.u); } } } void build(int i, int L, int R){ mi[i] = INF; if (L == R) return; int mid = (L + R) >> 1; build(lson); build(rson); } void update(int i, int L, int R, int l, int r, LL val){ if (l <= L && R <= r){ mi[i] = min(mi[i], val); return; } int mid = (L + R) >> 1; if (l <= mid) update(lson, l, r, val); if (r > mid) update(rson, l, r, val); } void query(int i, int L, int R, int x, LL &ans){ ans = min(ans, mi[i]); if (L == R) return; int mid = (L + R) >> 1; if (x <= mid) query(lson, x, ans); else query(rson, x, ans); } int main(){ scanf("%d%d%d%d", &n, &m, &s, &t); rep(i, 1, m){ int x, y, z; scanf("%d%d%d", &x, &y, &z); v[x].push_back({y, z}); g[y].push_back({x, z}); ++deg[y]; } getdag(); dij(s, ds, v); dij(t, dt, g); build(1, 1, n); rep(i, 1, n){ for (auto edge : v[i]){ if (a[i] + 1 < a[edge.u] && ds[i] != INF && dt[edge.u] != INF){ update(1, 1, n, a[i] + 1, a[edge.u] - 1, ds[i] + dt[edge.u] + edge.w); } } } scanf("%d", &q); while (q--){ int x; scanf("%d", &x); ans = INF; if (ds[x] == INF || dt[x] == INF){ printf("%lld\n", dt[s]); continue; } query(1, 1, n, a[x], ans); if (ans == INF) puts("-1"); else printf("%lld\n", ans); } return 0; }