「NOIP2013」货车运输
传送门
Luogu
解题思路
首先 \(\text{Kruskal}\) 一下,构造出一棵森林。
并查集还要用来判断连通性。
倍增 \(\text{LCA}\) 的时候顺便维护一下路径最小值即可。
细节注意事项
- 代码稍微有点长,不要出小问题
参考代码
#include<cstdio>
#include<algorithm>
using std::sort;
const int MAXN=1e4+10;
const int MAXM=5*1e4+10;
inline int min(int a,int b){return a<b?a:b;}
inline void swap(int& a,int& b){int t=a;a=b;b=t;}
inline int read(){
int s=0;bool f=false;char c=getchar();
while(c<'0'||c>'9')f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9')s=(s<<3)+(s<<1)+(c^48),c=getchar();
return (f)?(-s):(s);
}
int n,m,q;
struct edge{int u,v,w;}g[MAXM];
inline bool cmp(edge a,edge b){return a.w>b.w;}
int tot,ver[MAXM<<1],dis[MAXM<<1],nxt[MAXM<<1],fir[MAXN];
inline void Add_edge(int u,int v,int w){
nxt[++tot]=fir[u],fir[u]=tot,ver[tot]=v,dis[tot]=w;
nxt[++tot]=fir[v],fir[v]=tot,ver[tot]=u,dis[tot]=w;
}
int dad[MAXN];
inline int findd(int k){
return dad[k]==k?k:dad[k]=findd(dad[k]);
}
inline bool is_unionn(int u,int v){
return findd(u)==findd(v);
}
inline void unionn(int u,int v){
int fu=findd(u),fv=findd(v);
if(fu!=fv)dad[fv]=fu;
}
inline void Kruskal(){
for(int i=1;i<=n;i++)
dad[i]=i;
sort(g+1,g+m+1,cmp);
for(int i=1;i<=m;i++)
if(!is_unionn(g[i].u,g[i].v))
unionn(g[i].u,g[i].v),Add_edge(g[i].u,g[i].v,g[i].w);
}
bool vis[MAXN];
int dep[MAXN],f[MAXN][22],w[MAXN][22];
inline void dfs(int u){
vis[u]=true;
for(int v,i=fir[u];i;i=nxt[i])
if(!vis[v=ver[i]])
dep[v]=dep[u]+1,f[v][0]=u,w[v][0]=dis[i],dfs(v);
}
inline int LCA(int x,int y){
if(!is_unionn(x,y)) return -1;
int ans=2147483647;
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;--i)
if(dep[f[x][i]]>=dep[y])
ans=min(ans,w[x][i]),x=f[x][i];
if(x==y) return ans;
for(int i=20;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];
return min(ans,min(w[x][0],w[y][0]));
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++)
g[i].u=read(),g[i].v=read(),g[i].w=read();
Kruskal();
for(int i=1;i<=n;i++)
if(!vis[i]){
dep[i]=1;
dfs(i);
f[i][0]=i;
w[i][0]=2147483647;
}
for(int i=1;i<=20;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]);
q=read();
for(int x,y,i=1;i<=q;i++)
x=read(),y=read(),printf("%d\n",LCA(x,y));
return 0;
}
完结撒花 \(qwq\)