可以發現可以構建出的是一棵樹,且樹的深度在20層及以內
剛開始想對於每條路徑跑最短路,然后都跑一邊得出答案,但是發現因為路徑可以重疊,所以后面求的路徑會修改一些公共路徑的最短路,所以不能這么求
考慮什么是不變的,一個點到自己的最短路一定是0,所以從每個點出發,跑它到所有子節點的最短路,這個路一定是這兩個點最終的最短路,而且因為這是一個二叉樹,所以復雜度為
\(T(n) = 2*T(n/2) + nlogn\)
大約是\(O(n(logn)^2)\)
然后對於每次詢問,找所有的公共祖先,求解即可
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
typedef pair<ll, int> P;
vector < P > edge[N];
ll f[N][30];
bool vis[N];
void cmin(ll & a, ll b) { a = min(a, b); }
int main() {
int n, m;
scanf("%d%d", &n, &m);
memset(f, 0x3f, sizeof(f));
for (int i = 1; i <= m; i++) {
int u, v, j; ll w;
scanf("%d%d%lld", &u, &v, &w);
if (u > v) swap(u, v);
edge[u].emplace_back(v, w);
edge[v].emplace_back(u, w);
for (j = 0; (v >> j) != u; j++);
cmin(f[v][j], w);
}
for (int i = 1; i <= n; i++) {
priority_queue < P, vector < P >, greater < P > > Q;
vector < int > c;
Q.emplace(0, i);
int j; f[i][0] = 0;
while (!Q.empty()) {
P u = Q.top(); Q.pop();
if (vis[u.second]) continue;
vis[u.second] = true; c.emplace_back(u.second);
for (j = 0; (u.second >> j) != i; j++);
cmin(f[u.second][j], u.first);
for (auto x:edge[u.second]) {
if (!vis[x.first] && x.first >= i)
Q.emplace(u.first + x.second, x.first);
}
}
for (auto x:c) vis[x] = false;
}
int q; scanf("%d", &q);
while (q--) {
int u, v, j = 0; scanf("%d %d", &u, &v);
ll ans = (1ll << 60);
for (int i = 0; i < 28; i++) {
while ((v >> i) < (u >> j)) j++;
if ((v >> i) == (u >> j))
cmin(ans, f[u][j] + f[v][i]);
}
if (ans > 60ll * 1e9) puts("-1");
else printf("%lld\n", ans);
}
return 0;
}