解题思路
首先,我们要求出最大生成树。这样做的原因是司机为了让自己能过通过载运更多的货物,显然会选择边权大的两边,由此可以推出我们要求的是最大生成树,去除原来的图中边权比较小的那些边。
得到了这样一个树之后,我们便考虑如何求出两个节点之间最小边权的最大值(即为题中的最大载重),因为这两点之间的路径是唯一的,我们只需要找出这条路径便可以得到答案。我们可以通过LCA来做到这一点。
这一步是LCA一个经典运用:静态树上链的权值查询问题。具体做法是在求出f数组的同时顺便求出一个dis数组,
d
i
s
i
,
j
dis_{i,j}
disi,j表示从i点出发走了2^j步所经过的边的边权最小值
初始:
d
i
s
i
,
0
=
l
e
n
(
i
,
f
i
,
0
)
dis_{i,0}=len(i,f_{i,0})
disi,0=len(i,fi,0)
转移方程:
d
i
s
i
,
j
=
m
i
n
(
d
i
s
i
,
j
−
1
,
d
i
s
f
i
,
j
−
1
,
j
−
1
)
dis_{i,j}=min(dis_{i,j-1},dis_{f_{i,j-1},j-1})
disi,j=min(disi,j−1,disfi,j−1,j−1)
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int INF=2147483600;
int n,m,k,q,x,y,fa[50010],head[10010],v[10010],dep[10010],lg[10010],f[10010][25],dis[10010][25];
struct c{
int x,w,next;
}a[100010];
struct cc{
int x,y,w;
}lyx[50010];
void add(int x,int y,int w)
{
++k;
a[k].x=y;
a[k].next=head[x];
a[k].w=w;
head[x]=k;
}
bool cmp(cc l,cc r){
return l.w>r.w;
}
int find(int x){
if(fa[x]!=x)return fa[x]=find(fa[x]);
return x;
}
void kruskal(){
sort(lyx+1,lyx+m+1,cmp);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
int xx=find(lyx[i].x),yy=find(lyx[i].y);
if(xx!=yy)
{
fa[xx]=yy;
add(xx,yy,lyx[i].w);
add(yy,xx,lyx[i].w);
}
}
return;
}
void dfs(int x,int fa){
v[x]=1;
dep[x]=dep[fa]+1;
for(int i=1;i<=lg[dep[x]];i++)
{
f[x][i]=f[f[x][i-1]][i-1];
dis[x][i]=min(dis[x][i-1],dis[f[x][i-1]][i-1]);
}
for(int i=head[x];i;i=a[i].next)
{
int y=a[i].x;
if(v[y])continue;
f[y][0]=x;
dis[y][0]=a[i].w;
dfs(y,x);
}
return;
}
int lca(int x,int y)
{
int ans=INF;
if(find(x)!=find(y))
return -1;
if(dep[x]>dep[y])swap(x,y);
while(dep[y]>dep[x])
{
ans=min(ans,dis[y][lg[dep[y]-dep[x]]]);
y=f[y][lg[dep[y]-dep[x]]];
}
if(x==y)return ans;
for(int i=lg[dep[x]];i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
ans=min(min(dis[x][i],dis[y][i]),ans);
x=f[x][i];
y=f[y][i];
}
}
ans=min(ans,min(dis[x][0],dis[y][0]));
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&lyx[i].x,&lyx[i].y,&lyx[i].w);
kruskal();
lg[0]=-1;
for(int i=1;i<=n;i++)
lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++)
{
if(!v[i])
{
dfs(i,0);
dis[i][0]=INF;
}
}
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
}