P3238 [HNOI2014]道路堵塞

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;
}
posted @ 2022-09-28 10:03  azzc  阅读(21)  评论(0编辑  收藏  举报