题面
略
简要题解
最大生成树+LCA
简要做法:
求出最大生成树,可以证明汽车一定要在最大生成树上跑是最优的
然后用倍增LCA求出货车要跑的点对(x, y)路径上的最小边权
证明:
由于每条路上有限制重量,我们的目标是让每条路径的最小边权最大
倘若货车走的是非最大生成树上的边,设该条边权为 w w w,连接 ( x , y ) (x, y) (x,y), 则由于最大生成树的性质,树上路径 ( x , y ) (x, y) (x,y)任意一条边的限重都大于 w w w,均会更优
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
#define _(d) while(d(isdigit(ch=getchar())))
#define inf 0x7ffff
template <class T> void g(T&t) {T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=2e5+4;
int fa[N],F[N][23],fa1[N][23],n,m,tot,d[N];
struct E{int to,nxt,lim;}e[N<<1];
int head[N];
void ins(int x,int y,int z){
e[++tot]=E{y,head[x],z},head[x]=tot;
}
struct Edge{int x,y,w;}ee[N];
int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
bool cmp(Edge a,Edge b){return a.w>b.w;}
bool vis[N];
void dfs(int x){
if(vis[x]) return; vis[x]=1;
for(int i=head[x];i;i=e[i].nxt){
if(vis[e[i].to]) continue;
F[e[i].to][0]=e[i].lim;
fa1[e[i].to][0]=x;
d[e[i].to]=d[x]+1;
dfs(e[i].to);
}
}
void work(int x,int y){
int ans=1e9;
if(d[x]<d[y]) swap(x,y);
repd(i,20,0) if(d[fa1[x][i]]>=d[y]) ans=min(ans,F[x][i]),x=fa1[x][i];
if(x==y) {
printf("%d\n",ans);
return ;
}
repd(i,20,0){
if(fa1[x][i]!=fa1[y][i]) {
ans=min(ans,F[x][i]);
ans=min(ans,F[y][i]);
x=fa1[x][i],y=fa1[y][i];
}
}
ans=min(ans,min(F[x][0],F[y][0]));
printf("%d\n",ans);
}
int main(){
g(n),g(m);
memset(F,1,sizeof(F));
rep(i,1,n) fa[i]=i;
rep(i,1,m) g(ee[i].x),g(ee[i].y),g(ee[i].w);
sort(ee+1,ee+1+m,cmp);
rep(i,1,m){
int f1=getfa(ee[i].x),f2=getfa(ee[i].y);
if(f1!=f2){
fa[f1]=f2;
ins(ee[i].x,ee[i].y,ee[i].w);
ins(ee[i].y,ee[i].x,ee[i].w);
}
}
rep(i,1,n) if(!vis[i]) d[i]=1,dfs(i),fa1[i][0]=i,F[i][0]=inf;
rep(j,1,20)
rep(i,1,n) fa1[i][j]=fa1[fa1[i][j-1]][j-1];
rep(j,1,20) rep(i,1,n){
F[i][j]=min(F[i][j],min(F[i][j-1],F[fa1[i][j-1]][j-1]));
}
int Q;g(Q);
while(Q--){
int x,y;g(x),g(y);
if(getfa(x)!=getfa(y)){printf("-1\n");continue;}
work(x,y);
return 0;
}