题目描述:
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。
现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入格式:
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行三个整数 x, y, z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。
注意: x != y,两座城市之间可能有多条道路 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x,y 之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,保证 x != y
输出格式:
共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。
如果货车不能到达目的地,输出 -1。
数据范围:
1 <= n <=1e4 1 <= m <=1e5 1 <= q <=3e4 1<= z <=1e5
解题报告: 无向带权图
题目是求两点之间任意可达路径上最小边权的最大值,所以要想办法选取尽量边权值大的边进行运输,那么权值较小的应该被舍弃。不妨够造最大生成树,得到最大生成树后,我们可以树上倍增求出任意两节点的最小载重量。
注意判断不可达情况即不在同一联通块。
#define first f
#define second s
#define ll long long
#define mp make_pair
#define pb push_back
#define pf push_front
#define lb lower_bound
#define ub upper_bound
#include <bits/stdc++.h>
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=5e4+5;
const int MOD=1e9+7;
const double PI=acos(-1);
const double e=2.718281828459;
struct node
{
int x,y,z;
}p[maxn];
vector<pii>edge[maxn];
int n,m,q;
bool vis[maxn];
int deep[maxn],f[maxn];
int ans[maxn][25],fa[maxn][25];
bool cmp(node a,node b){return a.z>b.z;}
int getfind(int x)
{
return x==f[x]?x:f[x]=getfind(f[x]);
}
void Kruskal()
{
sort(p+1,p+m+1,cmp);
for(int i=1;i<=n;i++){f[i]=i;}
for(int i=1;i<=m;i++){
int k1=getfind(p[i].x);
int k2=getfind(p[i].y);
if(k1!=k2){
f[k2]=k1;
edge[p[i].x].pb({p[i].y,p[i].z});
edge[p[i].y].pb({p[i].x,p[i].z});
}
}
}
void dfs(int now)
{
vis[now]=true;
for(int i=0;i<edge[now].size();i++){
pii pp=edge[now][i];
if(vis[pp.f]){continue;}
fa[pp.f][0]=now;
deep[pp.f]=deep[now]+1;
ans[pp.f][0]=pp.s;
dfs(pp.f);
}
}
int LCA_RMQ(int x,int y)
{
int mi=1e9+7;
if(deep[x]<deep[y]){swap(x,y);}
for(int i=20;i>=0;i--){
if(deep[fa[x][i]]>=deep[y]){
mi=min(mi,ans[x][i]);
x=fa[x][i];
}
}
if(x==y){return mi;}
for(int i=20;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
mi=min(mi,ans[x][i]);
mi=min(mi,ans[y][i]);
x=fa[x][i];y=fa[y][i];
}
}
return min(mi,min(ans[x][0],ans[y][0]));
}
int main()
{
mem(vis,false);
int x,y,z;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
p[i]={x,y,z};
}
Kruskal();
for(int i=1;i<=n;i++){
if(!vis[i]){
deep[i]=1;
dfs(i);
ans[i][0]=MOD;
fa[i][0]=i;
}
}
for(int i=1;i<=20;i++){
for(int j=1;j<=n;j++){
fa[j][i]=fa[fa[j][i-1]][i-1];
ans[j][i]=min(ans[j][i-1],ans[fa[j][i-1]][i-1]);
}
}
scanf("%d",&q);
while(q--){
scanf("%d%d",&x,&y);
if(getfind(x)!=getfind(y)){printf("-1\n");}
else{printf("%d\n",LCA_RMQ(x,y));}
}
return 0;
}