前置知识: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;
}