「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\)

猜你喜欢

转载自www.cnblogs.com/zsbzsb/p/11745779.html