BZOJ 3732: Network(Kruskal重构树)

传送门

解题思路

  \(Kruskal\)重构树模板题,\(Kruskal\)重构树就是在建最小生成树加边的时候,不直接加边,而是新建一个点,而这个点的权值就是边权,这个新建的点作为原先点的父亲,并且把他们并起来。最终会得到一棵树,这个树有很多优秀的性质,首先它的叶结点都为原先的点,非叶结点为原先的边,还有从向下权值单调不减。那么这道题其实就算把\(Kruskal\)重构树建出来后两个点\(LCA\)的权值。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=30005;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;
}

int n,m,q,f[N][20],head[N],to[N],nxt[N],w[N],tot;
int F[N],cnt,num,dep[N];
struct Edge{
    int u,v,w;
    friend bool operator<(const Edge A,const Edge B){
        return A.w<B.w;
    }
}edge[N];

int get(int x){
    if(x==F[x]) return x;
    return F[x]=get(F[x]);
}

inline void add(int bg,int ed){
    to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
}

void dfs(int x,int FA){
    f[x][0]=FA;
    for(int i=1;i<=16;i++) 
        f[x][i]=f[f[x][i-1]][i-1];
    for(int i=head[x];i;i=nxt[i])
        dep[to[i]]=dep[x]+1,dfs(to[i],x);
}

inline int lca(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=16;~i;i--)
        if(dep[f[x][i]]>=dep[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=16;~i;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}

int main(){
    n=rd(),m=rd(),q=rd();num=n;
    for(int i=1;i<=n;i++) F[i]=i;
    for(int i=1;i<=m;i++)
        edge[i].u=rd(),edge[i].v=rd(),edge[i].w=rd();
    sort(edge+1,edge+1+m);int x,y;
    for(int i=1;i<=m;i++){
        x=get(edge[i].u),y=get(edge[i].v);
        if(x==y) continue;tot++;
        F[x]=y;w[++num]=edge[i].w;F[num]=num;
        F[x]=num;F[y]=num;add(num,x);add(num,y);
        if(tot==n-1) break;
    }
    dfs(num,0);
    while(q--){
        x=rd(),y=rd();
        printf("%d\n",w[lca(x,y)]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sdfzsyq/p/10274677.html