这个题目想A掉两个多月了,今天终于AC了,好开心 _
题意是 有一个有n个点m条边的图,每次询问两个点路径上最小边权的最大值。
根据最大生成树的性质,先kruskal求出最大生成树,有g存储新的生成树。
然后倍增相当于在树上求出两两点的路径上最小边权的最大值。
之后通过dfs解决 f [ i ] [ 0 ] , w [ i ] [ 0 ] , d e p [ i ] f[i][0],w[i][0],dep[i] f[i][0],w[i][0],dep[i]等
这个可以用 L C A LCA LCA解决。
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示i的第
2
j
2^j
2j个父亲
w
[
i
]
[
j
]
w[i][j]
w[i][j]表示i到第
2
j
2^j
2j个父亲这一段区间中最小边权的值。
调用的时候
f
[
i
]
[
j
]
=
f
[
f
[
i
]
[
j
−
1
]
]
[
j
−
1
]
f[i][j]=f[f[i][j-1]][j-1]
f[i][j]=f[f[i][j−1]][j−1]
i
i
i的第
2
j
2^j
2j个父亲=i的第
2
j
−
1
2^{j-1}
2j−1个父亲的
2
j
−
1
2^{j-1}
2j−1个父亲
w
[
i
]
[
j
]
=
m
i
n
(
w
[
i
]
[
j
−
1
]
,
w
[
f
[
i
]
[
j
−
1
]
]
[
j
−
1
]
)
w[i][j]=min(w[i][j-1],w[f[i][j-1]][j-1])
w[i][j]=min(w[i][j−1],w[f[i][j−1]][j−1]) 同理
这个枚举必须先j再i,不然WA10.
之后都是常规的 L C A LCA LCA
先保证x的深度< y的深度,
然后跳y,跳到与x同样深度,之后x,y一起跳,如果 f [ x ] [ i ] = f [ y ] [ i ] f[x][i]=f[y][i] f[x][i]=f[y][i]说明可能跳过了,要缩小i。直到 f [ x ] [ 0 ] = f [ y ] [ 0 ] f[x][0]=f[y][0] f[x][0]=f[y][0]
#include <bits/stdc++.h>
using namespace std ;
const int N = 10010 ;
const int M = 50010 ;
const int inf = 999999999 ;
struct edge{
int from,to,w ;
}e[M];
struct node{
int to,next,w ;
}g[M<<1];
int dad[N],head[N],dep[N],w[N][25],f[N][25],vis[N] ;
int n,m,Q,tot ;
int find(int x){
return (dad[x]==x)?x:dad[x]=find(dad[x]) ;
}
bool cmp(edge a,edge b){
return a.w>b.w ;
}
void add(int x,int y,int w){
g[++tot].to=y ;
g[tot].w=w ;
g[tot].next=head[x] ;
head[x]=tot ;
}
void kruskal(){
for (int i=1;i<=n;i++) dad[i]=i ;
sort(e+1,e+m+1,cmp) ;
for (int i=1;i<=m;i++){
int X=find(e[i].from),Y=find(e[i].to) ;
if (X!=Y){
dad[X]=Y ;
add(e[i].from,e[i].to,e[i].w) ;
add(e[i].to,e[i].from,e[i].w) ;
}
}
}
void dfs(int rt){ //预处理
vis[rt]=true;
for (int i=head[rt];i;i=g[i].next){
int to=g[i].to;
if (vis[to]) continue ;
dep[to]=dep[rt]+1 ;
w[to][0]=g[i].w ;
f[to][0]=rt ;
dfs(to) ;
}
}
int lca(int x,int y){
if (find(x)!=find(y)) return -1 ;
int ans=inf ;
if (dep[x]>dep[y]) swap(x,y) ;//保证x的深度<y的深度,跳y
for (int i=20;i>=0;i--){
if (dep[x]<=dep[f[y][i]]){
ans=min(ans,w[y][i]) ;
y=f[y][i] ;
}
}
if (x==y) return ans ;
for (int i=20;i>=0;i--){
if (f[x][i]!=f[y][i]){
ans=min(ans,min(w[x][i],w[y][i])) ;
x=f[x][i] ;
y=f[y][i] ;
}
}
ans=min(ans,min(w[x][0],w[y][0])) ;
return ans ;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w) ;
kruskal() ;
for (int i=1;i<=n;i++){
if (!vis[i]){
dep[i]=1 ;
dfs(i);
w[i][0]=inf ;
f[i][0]=i ;
}
}
for (int j=1;j<=20;j++){
for (int i=1;i<=n;i++){
f[i][j]=f[f[i][j-1]][j-1] ;
w[i][j]=min(w[i][j-1],w[f[i][j-1]][j-1]) ;
}
}
scanf("%d",&Q) ;
for (int i=1;i<=Q;i++){
int a,b ;
scanf("%d%d",&a,&b) ;
printf("%d\n",lca(a,b)) ;
}
}