$des$
给定一张 $n$ 个点 $m$ 条边的带权无向联通图,$q$ 次询问,每次询问 $u_i$ 到 $v_i$ 的最短
路长度。
$n,q <= 10^5, m - n <= 20$
$sol$
首先随便搞一棵生成树,那么会有一些边不在生成树上。
把这些边的端点标记为特殊点。
对于一个询问,如果最短路只经过生成树上的边,就可以直接计算。
否则一定经过了一个特殊点,可以枚举这个特殊点,然后更新答案
$code$
#include <bits/stdc++.h> using namespace std; #define gc getchar() inline int read() { int x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } #define LL long long #define Rep(i, a, b) for(int i = a; i <= b; i ++) const int N = 1e5 + 10; int Now; int cnt, head[N], cnt2, head2[N]; struct Node { int u, v, w, nxt; bool used; } E[N], Gr[N << 1], G[N << 1]; int n, m; int Nottree[50], tot; int fat[N]; int Get(int x) { return fat[x] == x ? x : fat[x] = Get(fat[x]); } void Link(int u, int v, int w) { G[++ cnt].v = v; G[cnt].w = w; G[cnt].nxt = head[u]; head[u] = cnt; } void Link_g(int u, int v, int w) { Gr[++ cnt2].v = v; Gr[cnt2].w = w; Gr[cnt2].nxt = head2[u]; head2[u] = cnt2; } void Kruskal() { int js = 0; Rep(i, 1, m) { int u = E[i].u, v = E[i].v; int fau = Get(u), fav = Get(v); if(fau != fav) { fat[fau] = fav; js ++; Link(u, v, E[i].w); Link(v, u, E[i].w); E[i].used = 1; } if(js == n - 1) break; } } struct Short { LL u, dis_; bool operator < (const Short a) const { return this-> dis_ > a.dis_; } }; LL dis[50][N]; bool vis[N]; priority_queue <Short> Q; void Dijkstra(int start) { Rep(i, 1, n) dis[Now][i] = 1e18, vis[i] = 0; Q.push((Short) {start, dis[Now][start] = 0}); while(!Q.empty()) { Short tp = Q.top(); Q.pop(); if(vis[tp.u]) continue; vis[tp.u] = 1; for(int i = head2[tp.u]; ~ i; i = Gr[i].nxt) { int v = Gr[i].v; if(dis[Now][v] > dis[Now][tp.u] + Gr[i].w) { dis[Now][v] = dis[Now][tp.u] + Gr[i].w; Q.push((Short) {v, dis[Now][v]}); } } } } int fa[N], size[N], son[N], topp[N]; LL deep[N]; void Dfs1(int u, int f_, LL dep) { size[u] = 1; fa[u] = f_; deep[u] = dep; for(int i = head[u]; ~ i; i = G[i].nxt) { int v = G[i].v; if(v == f_) continue; Dfs1(v, u, dep + G[i].w); size[u] += size[v]; if(size[v] > size[son[u]]) son[u] = v; } } void Dfs2(int u, int tp) { topp[u] = tp; if(!son[u]) return ; Dfs2(son[u], tp); for(int i = head[u]; ~ i; i = G[i].nxt) { int v = G[i].v; if(v != fa[u] && v != son[u]) Dfs2(v, v); } } inline int Lca(int x, int y) { int tpx = topp[x], tpy = topp[y]; while(tpx != tpy) { if(deep[tpx] < deep[tpy]) swap(x, y), swap(tpx, tpy); x = fa[tpx], tpx = topp[x]; } if(deep[x] < deep[y]) swap(x, y); return y; } int main() { n = read(), m = read(); Rep(i, 1, n) head[i] = -1, head2[i] = -1; Rep(i, 1, n) fat[i] = i; Rep(i, 1, m) { int u = read(), v = read(), w = read(); E[i] = (Node) {u, v, w, 0, 0}; Link_g(u, v, w), Link_g(v, u, w); } Kruskal(); Rep(i, 1, m) if(E[i].used == 0) Nottree[++ tot] = E[i].u, Nottree[++ tot] = E[i].v; Rep(i, 1, tot) { Now ++; Dijkstra(Nottree[i]); } Dfs1(1, 0, 1); Dfs2(1, 1); for(int q = read(); q; q --) { int u = read(), v = read(); LL Answer = deep[u] + deep[v] - 2 * deep[Lca(u, v)]; Rep(i, 1, tot) { Answer = min(Answer, dis[i][u] + dis[i][v]); } cout << Answer << ' '; } return 0; }