给定一个树,在树上加k条边,求全源最短路。(\(n \le 10^5 \space, k \le 20\))
显然利用树的性质,考虑如何处理加的20条边即可。可以枚举所有经过的非树边,对每个非树边的端点依次更新答案,再结合树上路径长度即可。
最小生成树+lca+dij即可解决的一道紫题...
写的时候要注意不同的图、树的混淆问题。
把lca板子写错调了一小时??? 有时候对树上深度总有种从下到上的错觉。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <assert.h>
#include <map>
#define ll long long
using namespace std;
const ll N = 100005, M = 200005,INF = 1e14;
ll n, m, Q;
ll cnt1, head1[M], cnt2, head2[M];
ll cnt, vis[N], dep[N], fa[N], f[N][23];
ll dis[45][N], treedis[N], tot,await[N];
struct edge {
ll from, to, next;
ll dis;
} e1[M], e2[M];
struct EDGE {
ll u, v, d;
} e[M];
int read() {
register int x=0,f=1;
register char s=getchar();
while(s>'9'||s<'0') {
if(s=='-') f=-1;
s=getchar();
}
while(s>='0'&&s<='9') {
x=x*10+s-'0';
s=getchar();
}
return x*f;
}
void add1(ll u, ll v, ll dis) {
e1[++cnt1].from = u;
e1[cnt1].to = v;
e1[cnt1].next = head1[u];
e1[cnt1].dis = dis;
head1[u] = cnt1;
}
void add2(ll u, ll v, ll dis) {
e2[++cnt2].to = v;
e2[cnt2].from = u;
e2[cnt2].next = head2[u];
e2[cnt2].dis = dis;
head2[u] = cnt2;
}
int cmp(EDGE a, EDGE b) {
return a.d < b.d;
}
ll find(ll k) {
return fa[k] == k ? k : fa[k] = find(fa[k]);
}
void dij(ll k) {
for (int i=1;i<=n;i++)
vis[i]=0,dis[k][i]=INF;
priority_queue<pair<ll,int> > q;
dis[k][await[k]] = 0ll;
q.push(make_pair(0,await[k]));
while (!q.empty()) {
ll x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (ll i = head1[x]; i; i = e1[i].next) {
ll v = e1[i].to;
if (dis[k][v] > dis[k][x] + e1[i].dis) {
dis[k][v] = dis[k][x] + e1[i].dis;
q.push(make_pair(-dis[k][v],v));
}
}
}
}
void dfs(ll k) {
for (int i=1; i<=20; i++) f[k][i]=f[f[k][i-1]][i-1];
for (ll i = head2[k]; i; i = e2[i].next) {
ll v = e2[i].to;
if (v == f[k][0]) continue;
f[v][0]=k;
treedis[v]=treedis[k]+e2[i].dis;
dep[v]=dep[k]+1;
dfs(v);
}
}
ll lca(ll a, ll b) {
if (dep[a] < dep[b]) swap(a, b);
for (ll i = 20; i >= 0; i--)
if (dep[f[a][i]] >= dep[b])
a = f[a][i];
if (a == b) return a;
for (ll i = 20; i >= 0; i--)
if (f[a][i] != f[b][i]) a = f[a][i], b = f[b][i];
return f[a][0];
}
int main() {
n=read(),m=read();
for (ll i = 1; i <= n; i++) fa[i] = i;
for (ll i = 1; i <= m; i++) {
e[i].u=read(),e[i].v=read(),e[i].d=read();
add1(e[i].u, e[i].v, e[i].d),add1(e[i].v, e[i].u, e[i].d);
}
sort(e + 1, e + 1 + m, cmp);
for (ll i = 1; i <= m; i++) {
ll f1 = find(e[i].u), f2 = find(e[i].v);
if (f1 != f2) {
add2(e[i].u, e[i].v, e[i].d);
add2(e[i].v, e[i].u, e[i].d);
fa[f1] = f2;
} else {
await[++cnt]=e[i].u;
await[++cnt]=e[i].v;
}
}
for (int i=1; i<=cnt; i++) dij(i);
cin >> Q;
dfs(1);
while (Q--) {
ll x = read(), y = read();
ll ans = treedis[x] + treedis[y] - 2 * treedis[lca(x, y)];
for (ll i = 1; i <= cnt; i++)
ans=min(ans,dis[i][x] + dis[i][y]);
cout << ans << endl;
}
}