CF1051F The Shortest Statement 題解
阿新 • • 發佈:2021-11-11
給定一個樹,在樹上加k條邊,求全源最短路。($n \le 10^5 \space, k \le 20$)
給定一個樹,在樹上加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; } }
本文來自部落格園,作者:Kinuhata,轉載請註明原文連結:https://www.cnblogs.com/KinuhataSaiai/p/15540964.html