1. 程式人生 > 其它 >CF1051F The Shortest Statement 題解

CF1051F The Shortest Statement 題解

給定一個樹,在樹上加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