2020.11.21
解法
连接两个点的那条最大值最小的路径一定在最小生成树上,而又要查询这个最大值是多少,那么就想到建出克鲁斯卡尔重构树。由于可能不连通,所以最后建出来的实际上是重构森林,记得要把每个连通块都遍历到。
对于节点的连通性,直接用之前维护好的并查集就好了,不连通就输出-1,连通的话再在重构树内倍增找LCA,最后输出LCA的权值(该节点所表示的边的边权)。
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 300007
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
struct E{
int next,to;
}e[N<<2];
struct E_{
int u,v,dis;
E_(int u=0,int v=0,int dis=0):u(u),v(v),dis(dis){}
bool operator <(const E_ x) const{
return dis<x.dis;
}
}L[N];
int n,m,Q,fa[N<<1],f[N<<1][20],val[N<<1],head[N<<1],cnt=0,dep[N<<1];
inline int find(int x){
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
inline void add(int id,int to){
e[++cnt]=(E){head[id],to};
head[id]=cnt;
}
bool vis[N<<1],tag[N<<1];
void dfs(int u){
for(int i=1;i<20;i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(vis[v]) continue;
dep[v]=dep[u]+1,vis[v]=1;
dfs(v);
}
}
inline void swap(int &x,int &y){x^=y,y^=x,x^=y;}
inline int Lca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int i=19;~i;i--)
if(dep[f[u][i]]>=dep[v])
u=f[u][i];
if(u==v) return u;
for(int i=19;~i;i--)
if(f[u][i]!=f[v][i])
u=f[u][i],v=f[v][i];
return f[u][0];
}
int main(){
// freopen("graph.in","r",stdin);
// freopen("graph.out","w",stdout);
n=read(),m=read(),Q=read();
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
L[i].u=read(),L[i].v=read(),L[i].dis=read();
sort(L+1,L+1+m);
int r=0;
for(int i=1;i<=m;i++){
int u=L[i].u,v=L[i].v;
int fa_x=find(u),fa_y=find(v);
if(fa_x==fa_y) continue;
++n;
fa[n]=fa[fa_x]=fa[fa_y]=n;
f[n][0]=f[fa_x][0]=f[fa_y][0]=n;
add(n,fa_x); add(n,fa_y);
val[n]=L[i].dis;
if((++r)==n-1) break;
}
for(int i=n;i;i--)
if(!vis[i]) dep[i]=vis[i]=1,dfs(i);
while(Q--){
int u=read(),v=read();
if(find(u)!=find(v)) printf("-1
");
else{
int lca=Lca(u,v);
printf("%d
",val[lca]);
}
}
}