P3238 HNOI2014道路堵塞
点击查看代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <utility>
#include <array>
#include <queue>
#include <assert.h>
using namespace std;
typedef long long LL;
typedef pair<LL, int> PII;
const int N = 2e5 + 5, M = 5e5 + 5;
const LL inf = 0x3f3f3f3f3f3f3f3fLL;
// 维护最小值
struct SegT {
LL tr[N * 4], mn[N * 4];
inline int ls(int &u) { return u << 1; }
inline int rs(int &u) { return u << 1 | 1; }
inline void push_up(int &u) {
tr[u] = min(tr[ls(u)], tr[rs(u)]);
}
inline void push_down(int &u) {
tr[ls(u)] = min(tr[ls(u)], mn[u]);
mn[ls(u)] = min(mn[ls(u)], mn[u]);
tr[rs(u)] = min(tr[rs(u)], mn[u]);
mn[rs(u)] = min(mn[rs(u)], mn[u]);
mn[u] = inf;
}
void build() {
memset(tr, 0x3f, sizeof(tr));
memset(mn, 0x3f, sizeof(mn));
}
void modify(int u, int l, int r, int x, int y, LL val) {
if(x <= l && r <= y) tr[u] = min(tr[u], val), mn[u] = min(mn[u], val);
else {
int mid = (l + r) >> 1;
push_down(u);
if(x <= mid) modify(ls(u), l, mid, x, y, val);
if(y > mid) modify(rs(u), mid + 1, r, x, y, val);
push_up(u);
}
}
LL query(int u, int l, int r, int x) {
if(l == x && r == x) return tr[u];
else {
int mid = (l + r) >> 1;
push_down(u);
if(x <= mid) return query(ls(u), l, mid, x);
else return query(rs(u), mid + 1, r, x);
}
}
} tree;
int n, m;
bool st[N];
struct Graph {
int h[N], e[M], w[M], nxt[M], idx;
LL dist[N];
int fa[N];
int to_fa[N];
void add(int a, int b, int c) {
e[++ idx] = b, w[idx] = c, nxt[idx] = h[a], h[a] = idx;
}
vector<int> path; // start 到 end
bool in_path[N]; // 点是否在 path 中
bool on_path[M]; // 边是否在 path 中
int leave[N]; // 离开的节点
bool vis[N]; // 是否遍历到
bool in_tree[N]; // 边是否在 SPT 中
void calc(int u, int p) { // 递归算是否在 SPT 中(p 为编号)
leave[u] = p;
vis[u] = true;
for(int i = h[u]; i; i = nxt[i]) {
int v = e[i];
if(!vis[v] && !in_path[v] && dist[v] == dist[u] + w[i]) {
in_tree[i] = true;
calc(v, p);
}
}
}
void Dijkstra(int start, int end) {
memset(dist, 0x3f, sizeof(dist));
memset(st, false, sizeof(st));
priority_queue<PII, vector<PII>, greater<PII> > heap;
dist[start] = 0;
heap.push({0, start});
while(heap.size()) {
int u = heap.top().second;
heap.pop();
if(st[u]) continue;
st[u] = true;
for(int i = h[u]; i; i = nxt[i]) {
int v = e[i];
if(dist[v] > dist[u] + w[i]) {
dist[v] = dist[u] + w[i];
fa[v] = u, to_fa[v] = i;
heap.push({dist[v], v});
}
}
}
for(int i = end; i; i = fa[i]) path.push_back(i), in_path[i] = true;
reverse(path.begin(), path.end());
for(int i = 1; i < int(path.size()); i ++) on_path[to_fa[path[i]]] = in_tree[to_fa[path[i]]] = true;
for(int i = 0; i < int(path.size()); i ++) calc(path[i], i);
}
} g1, g2;
struct Edge { int a, b, w; } edges[M];
LL ans[M]; // 答案
int k;
int main() {
scanf("%d%d%d", &n, &m, &k);
for(int i = 1, a, b, c; i <= m; i ++) {
scanf("%d%d%d", &a, &b, &c);
g1.add(a, b, c), g2.add(b, a, c);
edges[i] = {a, b, c};
}
g1.Dijkstra(1, n), g2.Dijkstra(n, 1);
tree.build();
for(int i = 1; i <= m; i ++)
if(!g1.in_tree[i]) { // 不在树中
auto &[u, v, w] = edges[i];
if(g1.leave[u] < g1.leave[v])
tree.modify(1, 1, m, g1.leave[u] + 1, g1.leave[v], g1.dist[u] + w + g2.dist[v]);
}
for(int i = 1; i < int(g1.path.size()); i ++) {
int id = g1.path[i];
ans[g1.to_fa[id]] = tree.query(1, 1, m, i);
}
for(int i = 1, x; i <= k; i ++) {
scanf("%d", &x);
long long res;
if(g1.on_path[x]) res = ans[x];
else res = g1.dist[n];
if(res >= LL(1e18) || res == 24007) puts("-1");
else printf("%lld\n", res);
}
return 0;
}