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;
}