题目大意:城市与城市之间有道路相连,并且道路有着限重,q次查询问,从x到y车的最大载重量,不能到达就输出-1.
解题思路:这道题有很多种解法,但这道题放在了倍增里,自然而然想着用倍增的方法去做,对于才初步了解这个算法的我来说,还是有点困难的。其实如果城市与城市之间有多条路径可以抵达,那只要保留那条载重最大的那条路径就行了。所以我们自然而然可以在它给的图上跑kruscal,跑出一颗最大生成树。然后在这颗树上我们就可以使用lca方法了,这是用来寻找最近公共祖先的,放到这里恰恰好。如果有最近的公共祖先那这两个城市就是相通的,反之无法到达。但要求最大载重量,那就还需要一个数组w[maxn][21],w[i][j],代表i节点到i的第2^j个父亲节点之间的最小载重量。
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+5;
int fa[maxn],lg[maxn],dep[maxn],n,m;
int we[maxn][21],f[maxn][21];
bool vis[maxn];
struct edge {
int s;
int e;
int w;
} ee[50005];
struct node {
int to;
int cost;
};
vector<node> G[10005];
bool cmp(edge x,edge y) {
return x.w>y.w;
}
int find(int x) {
if(fa[x]==x) return x;
return fa[x] = find(fa[x]);
}
bool cmb(int x,int y) {
x=find(x),y=find(y);
if(x==y) return false;
else {
fa[x] = y;
return true;
}
}
void kruscal() {
for(int i=1; i<=n+1; ++i) fa[i]=i;
for(int i=0; i<m; ++i) {
int s=ee[i].s,e=ee[i].e,w=ee[i].w;
if(cmb(s,e)) {
G[s].push_back(node {e,w});
G[e].push_back(node {s,w});
}
}
}
void dfs(int now,int last) {
dep[now]=dep[last]+1;
vis[now]=true;
f[now][0]=last;
for(int i=1; (1<<i)<=dep[now]; ++i) {
we[now][i]=min(we[now][i-1],we[f[now][i-1]][i-1]);
f[now][i]=f[f[now][i-1]][i-1];
}
for(int i=0; i<(int)G[now].size(); ++i) {
if(G[now][i].to!=last) {
we[G[now][i].to][0]=G[now][i].cost;
dfs(G[now][i].to,now);
}
}
}
int lca(int x,int y) {
if(find(x)!=find(y)) {
return -1;
}
if(dep[x]>dep[y]) swap(x,y);
int ans=inf;
while(dep[x]!=dep[y]) {
int len=dep[y]-dep[x];
ans=min(ans,we[y][lg[len]-1]);
y=f[y][lg[len]-1];
}
if(x==y) return ans;
for(int i=lg[dep[x]]-1; i>=0; --i) {
if(f[x][i]!=f[y][i]) {
ans=min(ans,min(we[x][i],we[y][i]));
x=f[x][i];
y=f[y][i];
}
}
ans=min(ans,min(we[x][0],we[y][0]));
return ans;
}
int main() {
scanf("%d%d",&n,&m);
int x,y,w;
for(int i=0; i<m; ++i) {
scanf("%d%d%d",&x,&y,&w);
ee[i]=edge {x,y,w};
}
sort(ee,ee+m,cmp);
kruscal();
for(int i=1; i<=n; ++i) {
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
}
for(int i=1; i<=n; ++i) {
if(!vis[i]) {
dfs(i,0);
}
}
int t;
scanf("%d",&t);
for(int i=1; i<=t; ++i) {
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
return 0;
}