简析
可以发现有一些权值较小的边是不会被走过的。正如样例中的第三条边,就算有其他的很多条边,这条边无论如何也是不会被走过的。于是我们想到了可以将图中这样的边去掉,按照这个思路我们便想到了构造最大生成树,将其余的边去除。
得到了这样一个树之后,我们便考虑如何求出两个节点之间最小边权的最大值(即为题中的最大载重),因为这两点之间的路径是唯一的,我们只需要找出这条路径便可以得到答案。我们可以通过 LCA 来做到这一点,我求 LCA 的方法是先从每一个根节点进行搜索,求出节点深度等信息,然后利用这些信息进行树上倍增。
于是我们可以得出大体思路:首先重新建图,构造出最大生成树,然后在最大生成树上求 LCA 来回答询问。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5,M=5e4+5;
struct edge2 {
int u,v,w;
bool operator<(const edge2 &x) const {
return w>x.w;
}
edge2() {}
edge2(int x,int y,int z) {
u=x,v=y,w=z;
}
};
vector<edge2> v;
int n,m,fa[N];
int getf(int x) {
return fa[x]==x?x:fa[x]=getf(fa[x]);
}
inline void merge(int x,int y) {
x=getf(x),y=getf(y),fa[x]=y;
}
struct edge {
int to,nxt,w;
} e[N<<1];
int cnt,head[N];
inline void add(int u,int v,int w) {
e[++cnt].to=v,e[cnt].w=w,e[cnt].nxt=head[u],head[u]=cnt;
}
int f[N][30],dep[N],w[N][30];
bitset<N> vis;
void build(int u,int fa) {
dep[u]=dep[fa]+1,f[u][0]=fa,vis[u]=1;
for(int i=head[u]; i; i=e[i].nxt) {
int v=e[i].to;
if(v==fa) {
continue;
}
w[v][0]=e[i].w,build(v,u);
}
}
int lca(int x,int y) {
if(getf(x)^getf(y)) {
return -1;
}
int ans=1e9;
if(dep[x]>dep[y]) {
swap(x,y);
}
for(int i=25; i>=0; i--) {
if(dep[f[y][i]]>=dep[x]) {
ans=min(ans,w[y][i]),y=f[y][i];
}
}
if(x==y) {
return ans;
}
for(int i=25; 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=0,x,y,z; i<m; i++) {
scanf("%d %d %d",&x,&y,&z),v.push_back(edge2(x,y,z));
}
sort(v.begin(),v.end());
for(int i=1; i<=n; i++) {
fa[i]=i;
}
int sum=1;
for(int i=0; i<m; i++) {
int x=v[i].u,y=v[i].v,z=v[i].w;
if(getf(x)^getf(y)) {
merge(x,y),add(x,y,z),add(y,x,z),sum++;
}
if(sum==n) {
break;
}
}
for(int i=1; i<=n; i++) {
if(!vis[i]) {
build(i,0),w[i][0]=1e9;
}
}
for(int i=1; i<=25; i++) {
for(int j=1; j<=n; j++) {
f[j][i]=f[f[j][i-1]][i-1],w[j][i]=min(w[j][i-1],w[f[j][i-1]][i-1]);
}
}
int q;
scanf("%d",&q);
for(int i=1,x,y; i<=q; i++) {
scanf("%d %d",&x,&y),printf("%d
",lca(x,y));
}
return 0;
}