題解:P7669 [JOI2018] Commuter Pass

喵仔牛奶發表於2024-09-03

Solution

我們有結論:答案路徑上免費的邊是連續的。

證明比較顯然,如果不連續就可以得出 \(S\to T\)\(U\to V\) 的更優路徑。

比較暴力的做法就是列舉免費路徑的起點和終點(我們記為 \(x,y\)),若 \(dis_{S,x}+dis_{y,T}+dis_{x,y}=dis_{S,T}\),用 \(dis_{U,x}+dis_{y,V}\) 更新答案。

我們要判斷 \((x,y)\) 這條路徑是否在最短路上,自然想到建最短路 DAG,\((x,y)\) 在最短路上的充要條件就是 \((x,y)\) 在最短路 DAG 上存在。

DAG 的可達性是很好的偏序關係。我們列舉 \(x\),令 \(mn_x\) 是所有可達的 \(y\) 中最小的 \(dis_{y,V}\),拓撲排序轉移即可。答案就是 \(\min\{dis_{U,x}+mn_x\}\)

當然,路徑正反不定,還要令 \(mn=\min dis_{U,y}\) 跑一遍,再和 \(\min\{dis_{x,V}+mn_x\}\) 取最小值。

時間複雜度 \(\mathcal{O}(\text{shortestpath}(n,m))\)(就是你選的最短路演算法的複雜度,比如我寫個 Dijkstra 就是 \(\mathcal{O}(m\log n)\))。

Code

#include <bits/stdc++.h>
#define REP(i, l, r) for (int i = (l); i <= (r); ++ i)
#define DEP(i, r, l) for (int i = (r); i >= (l); -- i)
#define fi first
#define se second
#define pb emplace_back
#define mems(x, v) memset((x), (v), sizeof(x))
using namespace std;
namespace Milkcat {
	typedef long long LL;
	typedef pair<LL, LL> pii;
	const int N = 1e6 + 5;
	LL n, m, s, t, p, q, u, v, w, sd[N], td[N], pd[N], qd[N], dg[N], mn1[N], mn2[N];
	vector<pii> G[N]; vector<int> E[N];
	void dijk(int s, LL* d) {
		priority_queue<pii, vector<pii>, greater<pii>> q;
		REP(i, 1, n) d[i] = 1e18;
		d[s] = 0, q.emplace(d[s], s);
		while (q.size()) {
			auto [dis, u] = q.top(); q.pop();
			if (dis != d[u]) continue;
			for (auto [v, w] : G[u])
				if (d[v] > d[u] + w) d[v] = d[u] + w, q.emplace(d[v], v);
		}
	}
	void chkmin(LL& x, LL y) { x = min(x, y); }
	int main() {
		cin >> n >> m >> s >> t >> p >> q;
		REP(i, 1, m) cin >> u >> v >> w, G[u].pb(v, w), G[v].pb(u, w);
		dijk(s, sd), dijk(t, td), dijk(p, pd), dijk(q, qd);
		REP(u, 1, n) {
			mn1[u] = pd[u], mn2[u] = qd[u];
			for (auto [v, w] : G[u])
				if (sd[u] + td[v] + w == sd[t]) E[u].pb(v), dg[v] ++;
		}
		queue<int> q; LL rs = 1e18;
		REP(i, 1, n) if (!dg[i]) q.push(i);
		while (q.size()) {
			int u = q.front(); q.pop();
			chkmin(rs, mn1[u] + qd[u]), chkmin(rs, mn2[u] + pd[u]);
			for (int v : E[u]) {
				chkmin(mn1[v], mn1[u]), chkmin(mn2[v], mn2[u]);
				if (!-- dg[v]) q.push(v);
			}
		}
		cout << rs << '\n';
		return 0;
	}
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int T = 1;
	while (T --) Milkcat::main();
	return 0;
}

相關文章