传送门
这个问题叫做『最大瓶颈路径』
最大瓶颈路径一定存在于最大生成树中/反证法:如果最大瓶颈路径不存在与最大生成树中。
这些不在最大生成树中的边会和最大生成树形成环。
我们删掉环上最小的边,保留这一条边,会得到一棵新的更大的生成树。
这与原来那棵树是最大生成树矛盾了。
注意,最短路不一定在最小生成树上(如一个环的情况)
现在问题转变为求树上两点的最小边权问题了。
很明显是从u->LCA(u,v)->v这条路能使最小边权最大。
我们先用Tarjan求出LCA.记录下来。
用一个数组记录DFS遍历的前一个节点和边权,然后递归分别找u->LCA(u,v)的最小权值,v->LCA(u,v)的最小权值
两者取min即为答案。
需要注意的是,加入询问的两个点不在一颗树上,Tarjan跑出的LCA其实是不对的,所以要在最后输出时去判断一下是否在一棵树中。
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxm=510000;
struct Node{
int net;
int to;
int cost;
int lca;
int ans;
};
bool vis[maxm];
Node edge[2][2*maxm];
int cnt[2],head[2][maxm],n,m;
int fatt[maxm],fat[maxm],dis[maxm];
int Dis1,Dis2;
int ansx[maxm],ansy[maxm];
int fatx[maxm];
void add(int id,int x,int y,int c)
{
edge[id][++cnt[id]].to=y;
edge[id][cnt[id]].cost=c;
edge[id][cnt[id]].net=head[id][x];
head[id][x]=cnt[id];
}
struct node{
int x,y,z;
}a[maxm];
int find1(int x)
{
if(x==fatt[x]) return x;
return fatt[x]=find1(fatt[x]);
}
int findx(int x)
{
if(x==fatx[x]) return x;
else
return fatx[x]=findx(fatx[x]);
}
int find(int id,int x,int fs)
{
if(id==0)
{
Dis1=1e17;
while(fat[x]!=x&&fs!=x)
{
Dis1=min(Dis1,dis[x]);
x=fat[x];
}
return x;
}
else
{
Dis2=1e17;
while(fat[x]!=x&&fs!=x)
{
Dis2=min(Dis2,dis[x]);
x=fat[x];
}
return x;
}
}
bool comp(const node&x,const node&y)
{
return x.z>y.z;
}
void dfs(int x)
{
vis[x]=1;
fat[x]=x;
fatx[x]=x;
for(int K=head[0][x];K;K=edge[0][K].net)
{
int p=edge[0][K].to;
if(vis[p]) continue;
dfs(p);
fatx[p]=x;
fat[p]=x;
dis[p]=edge[0][K].cost;
}
for(int i=head[1][x];i;i=edge[1][i].net)
{
int p=edge[1][i].to;
if(!vis[p]) continue;
//int ans=min(Dis1,Dis2);
//edge[1][i].ans=ans;
edge[1][i].lca=findx(p);
ansx[i]=x,ansy[i]=p;
if(i%2)
edge[1][i+1].lca=edge[1][i].lca,ansx[i+1]=x,ansy[i+1]=p;
else
edge[1][i-1].lca=edge[1][i].lca,ansx[i-1]=x,ansy[i-1]=p;
}
}
int main()
{
//freopen("truck.in","r",stdin);
//freopen("truck.out","w",stdout);
int maxf=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fatt[i]=i,fat[i]=i,fatx[i]=i;
for(int i=1,x,y,z;i<=m;i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
sort(a+1,a+m+1,comp);
int tot=0;
for(int i=1;i<=m&&tot!=n-1;i++)
if(find1(a[i].x)!=find1(a[i].y))
{
fatt[find1(a[i].x)]=find1(a[i].y);
add(0,a[i].x,a[i].y,a[i].z);add(0,a[i].y,a[i].x,a[i].z);
tot++;
}
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(1,x,y,0),add(1,y,x,0);
}
for(int i=1;i<=n;i++)
if(!vis[i])
dfs(i);
for(int i=1;i<=t;i++)
if(findx(ansx[2*i])!=findx(ansy[2*i]))
printf("-1\n");
else
{
find(0,ansx[2*i],edge[1][2*i].lca);
find(1,ansy[2*i],edge[1][2*i].lca);
printf("%d\n",min(Dis1,Dis2));
}
}