[NOIP2013 提高组] 货车运输 - 洛谷
核心思路
建最大生成树,树上维护倍增祖先,倍增最小值
#include<bits/stdc++.h>
#define INF 1e9+7
using namespace std;
const int N = 10005;
int n,m;
int val[N];
int f[N],deep[N];
bool vis[N];
int fa[N][22],w[N][22];
struct edge{
int u,v,w;
}e[N];
vector<edge> g[N];
void dfs(int u){
vis[u] = 1;
for(edge vv:g[u]){
int v = vv.v;
if(vis[v]) continue;
fa[v][0] = u;
w[v][0] = vv.w;
//cout<<u<<" "<<v<<" "<<vv.w<<endl;
deep[v] = deep[u]+1;
dfs(v);
}
}
bool cmp(edge a,edge b){
return a.w > b.w;
}
int find(int x){ //并查集寻找父节点
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
void hb(int u,int v){
f[find(u)] = find(v);
}
void kruskal(){
sort(e+1, e+m+1, cmp);
for(int i=1; i<=n; i++)
f[i]=i; //并查集初始化
for(int i=1; i<=m; i++){
if(find(e[i].u)!=find(e[i].v)){
hb(e[i].u,e[i].v);
g[e[i].u].push_back({0,e[i].v,e[i].w});
g[e[i].v].push_back({0,e[i].u,e[i].w}); //无向图,双向加边
}
}
return ;
}
int lca(int x, int y)
{
if(find(x)!=find(y)) return -1; //不连通,输出-1
int ans=INF;
if(deep[x]>deep[y]) swap(x,y);
for(int i=20; i>=0; i--)
if(deep[fa[y][i]]>=deep[x]){
//out<<w[y][i]<<endl;
ans=min(ans,w[y][i]);
y=fa[y][i];
}
if(x==y) return ans;
for(int i=20; i>=0; i--)
if(fa[x][i]!=fa[y][i]){
ans=min(ans, min(w[x][i], w[y][i]));
x=fa[x][i];
y=fa[y][i];
}
ans=min(ans, min(w[x][0], w[y][0]));
return ans;
}
int main(){
cin>>n>>m;
for(int i = 1;i <= m;i++){
int u,v,w;
cin>>u>>v>>w;
e[i].u = u,e[i].v = v,e[i].w = w;
}
kruskal();
for(int i=1; i<=n; i++)
if(!vis[i]){ //dfs收集信息
deep[i]=1;
dfs(i);
fa[i][0]=i;
w[i][0]=INF;
}
for(int i=1; i<=20; i++)
for(int j = 1;j <= n;j++){
fa[j][i]=fa[fa[j][i-1]][i-1];
w[j][i]=min(w[j][i-1],w[fa[j][i-1]][i-1]);
}
int q;
cin>>q;
while(q--){
int x,y;
cin>>x>>y;
cout<<lca(x,y)<<endl;
}
return 0;
}