货车运输(倍增 LCA 生成树)

传送门

前置知识:LCA 倍增 生成树

如果单纯求出从 1 号点到** n **号点的最小且最大的那条路,只需要灵活跑一遍
最短路就可以了

然而对于求任意两点之间的距离,上述方法就时间复杂度过大无法通过。考虑
到降低复杂度,此时选择使用倍增的方法,是的原本O(n)的时间复杂度降低为
logn

此时问题就在于如何使用倍增方法求解距离,借助求LCA的方法,可以得知求距离
的方法和求LCA的方法是一样的,因此距离也就能够求出来了

#include <bits/stdc++.h>
using namespace std;

const int N = 1e4 + 10;

int father[N], n, m, tot, head[N], dep[N], fa[N][22], value[N][22];
bool vis[N];
struct Edge{
	int u, v, next, w;
}edge[N << 3], edge1[N << 3];


void add(int u, int v, int w){
	edge[tot].v = v;
	edge[tot].w = w;
	edge[tot].next = head[u];
	head[u] = tot ++;
}

int find(int x){
	if(x == father[x])
		return x;
	else
		return father[x] = find(father[x]);
}
bool cmp(Edge a, Edge b){
	return a.w > b.w;
}
void kruskal(){
	sort(edge1 + 1, edge1 + 1 + m, cmp);
	int cnt = 0;
	for(int i = 1; i <= m; i ++){
		int a = edge1[i].u;
		int b = edge1[i].v;
		int aa = find(a), bb = find(b);
		if(aa == bb)
			continue;
		father[aa] = bb;
		cnt ++;
		add(a, b, edge1[i].w);
		add(b, a, edge1[i].w);
		if(cnt == n)
			return;
	}
}
void dfs(int now, int pre, int w){
	vis[now] = true;
	dep[now] = dep[pre] + 1;
	fa[now][0] = pre;
	value[now][0] = w;
	for(int i = head[now]; i != -1; i = edge[i].next){
		int v = edge[i].v;
		if(v != pre){
			dfs(v, now, edge[i].w);
		}
	}
}
int getlca(int u, int v){
	if(find(u) != find(v)){
		return -1;
	}
	if(dep[u] < dep[v])
		swap(u, v);
	int ans = 0x3f3f3f3f;
	while(dep[u] > dep[v]){
		ans = min(ans, value[u][(int)log2(dep[u] - dep[v])]);
		u = fa[u][(int)log2(dep[u] - dep[v])];
	}
	if(u == v)
		return ans;
	for(int i = 20; i >= 0; i --){
		if(fa[u][i] != fa[v][i]){
			ans = min(ans, value[u][i]);
			ans = min(ans, value[v][i]);
			u = fa[u][i];
			v = fa[v][i];
		}
	}
	ans = min(ans, min(value[u][0], value[v][0]));
	return ans;
}
int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i ++)
		father[i] = i;
	memset(head, -1, sizeof head);
	for(int i = 1; i <= m; i ++){
		int u, v, w;
		cin >> u >> v >> w;
		edge1[i].u = u;
		edge1[i].v = v;
		edge1[i].w = w;
	}
	kruskal();
	
	
	for(int i = 1; i <= n; i ++){
		if(!vis[i]){
			dfs(i, 0, 0);
		}
	}
	for(int j = 1; j <= 20; j ++){
		for(int i = 1; i <= n; i ++){
			fa[i][j] = fa[fa[i][j - 1]][j - 1];
			value[i][j] = min(value[i][j - 1], value[fa[i][j - 1]][j - 1]);
		}
	}
	int q;
	cin >> q;
	while(q --){
		int a, b;
		cin >> a >> b;
		cout << getlca(a, b) << endl;
	}
	
	return 0;
}
原文地址:https://www.cnblogs.com/pureayu/p/15171772.html