2010.10.30【NOIP2013】【洛谷P1967】货车运输(Kruskal重构树)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/83572760

传送门


解析:

K r u s k a l Kruskal 重构树裸题。

考虑在用 K r u s k a l Kruskal 建立图的最小生成树的时候,由于边是从小到大枚举的,所以每次连接两个连通块的边的边权就是两个连通块中的点之间路径上最大值的最小值。

那么这道题反过来求最大生成树也就做完了。

关于 K r u s k a l Kruskal 重构树的建法。

考虑有同学并没有做过NOI2018D1T1所以并不会建树(其实我也是在同步赛当天下午学习了这个知识),我在这里简要描述一下。

首先化边为点,在 K r u s k a l Kruskal 重构树中,除了叶子节点,其余节点代表的都是原图的边,节点权值就是原图边权。

然后每条边连接的两个连通块在重构树里面就是它的左右儿子。

差不多就是这样


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
    re int num;
    re char c;
    while(!isdigit(c=gc()));num=c^48;
    while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
    return num;
}

inline void outint(int a){
    static char ch[13];
    if(a==0)pc('0');
    while(a)ch[++ch[0]]=a-a/10*10,a/=10;
    while(ch[0])pc(ch[ch[0]--]^48);
}

cs int M=50004,N=10004;
struct edge{
    int u,v,w;
    friend bool operator<(cs edge  &a,cs edge &b){
        return a.w<b.w;
    }
}E[M];

struct Union_Find{
    int fa[N<<1];
    Union_Find(){for(int re i=0;i<N+N;++i)fa[i]=i;}
    inline int getfa(int x){
        while(x^fa[x])x=fa[x]=fa[fa[x]];
        return x;
    }
    inline void merge(int f,int u,int v){
        fa[getfa(v)]=fa[getfa(u)]=f;
    }
}S;

int n,m,lc[N<<1],rc[N<<1];
int w[N<<1];
int tot;
inline void Kruskal(){
    sort(E+1,E+m+1);
    tot=n;
    for(int re i=m;i;--i){
        int u=S.getfa(E[i].u),v=S.getfa(E[i].v);
        if(u==v)continue;
        lc[++tot]=u;
        rc[tot]=v;
        w[tot]=E[i].w;
        S.merge(tot,u,v);
    }
}

int top[N<<1],fa[N<<1],dep[N<<1],son[N<<1],siz[N<<1];
inline void dfs1(int u){
    siz[u]=1;
    if(lc[u]){
        int v=lc[u];
        fa[v]=u;
        dep[v]=dep[u]+1;
        dfs1(v);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
    if(rc[u]){
        int v=rc[u];
        fa[v]=u;
        dep[v]=dep[u]+1;
        dfs1(v);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
}

inline void dfs2(int u){
    if(lc[u]){
        int v=lc[u];
        top[v]=v;
        if(v==son[u])top[v]=top[u];
        dfs2(v);
    }
    if(rc[u]){
        int v=rc[u];
        top[v]=v;
        if(v==son[u])top[v]=top[u];
        dfs2(v);
    }
}

inline void tree_dissection(int root){
    dfs1(root);
    top[root]=root;
    dfs2(root);
}

inline int LCA(int u,int v){
    while(top[u]!=top[v]){
        if(dep[top[u]]>dep[top[v]])swap(u,v);
        v=fa[top[v]];
    }
    return dep[u]>dep[v]?v:u;
}

signed main(){
    n=getint();
    m=getint();
    for(int re i=1;i<=m;++i){
        E[i].u=getint();
        E[i].v=getint();
        E[i].w=getint();
    }
    Kruskal();
    for(int re i=1;i<=tot;++i)if(S.fa[i]==i)tree_dissection(i);
    int q=getint();
    while(q--){
        int u=getint(),v=getint();
        if(S.getfa(u)!=S.getfa(v)){
            puts("-1");
            continue;
        }
        outint(w[LCA(u,v)]);pc('\n');
    }
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/83572760