1. 程式人生 > >【BZOJ3732】Network(Kruskal重構樹)

【BZOJ3732】Network(Kruskal重構樹)

發現我還naive的不會Kruskal重構樹

所謂Kruskal重構樹 就是在做Kruskal的時候 構造一顆樹 對兩個即將合併的聯通塊 新建一個節點 作為這兩個聯通塊的父親 且這個節點的權值就是那條相連兩個聯通塊的權值

而且這棵樹很明顯是一個堆

那麼對於最初的最小生成樹 兩個節點路徑上的最大/小值 就是重構樹上他們的lca

然後就可以解決這道題了

#include<bits/stdc++.h>
#define N 15005
#define M 30005
using namespace std;
template<class T>
inline void read(T &x)
{
    x=0;
    static char ch=getchar();
    while(ch<'0'||ch>'9')   ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); 
}
int n,m,k;
struct Data
{
    int from,to,val;
}e[M];
int father[2*N],val[2*N];
inline bool cmp(const Data &a,const Data &b)
{
    return a.val<b.val;
}
inline int getfather(int x)
{
    if(father[x]==x)    return x;
    father[x]=getfather(father[x]);
    return father[x];
}
struct Edge
{
    int to,next,val;
}edge[4*N];
int first[2*N],tot;
inline void addedge(int x,int y)
{
    tot++; edge[tot].to=y; edge[tot].next=first[x]; first[x]=tot;
}
void Kruskal()
{
    int sign=n;
    for(int i=1;i<=2*n;i++) father[i]=i;
    sort(e+1,e+m+1,cmp);    
    for(int i=1;i<=m;i++)
    {
        int fx=getfather(e[i].from),fy=getfather(e[i].to);
        if(fx!=fy)
        {
            father[fx]=father[fy]=++sign;
            val[sign]=e[i].val;
            addedge(sign,fx); addedge(fx,sign);
            addedge(sign,fy); addedge(fy,sign);
            if(sign==2*n-1) break;
        }
    }
}
int depth[2*N],up[2*N][23];
void dfs(int now,int fa)
{
    depth[now]=depth[fa]+1;
    up[now][0]=fa;
    for(int i=1;i<=20;i++)  up[now][i]=up[up[now][i-1]][i-1];
    for(int u=first[now];u;u=edge[u].next)
    {
        int vis=edge[u].to;
        if(vis==fa) continue;
        dfs(vis,now);
    }
}
inline int lca(int x,int y)
{
    if(depth[x]<depth[y])   swap(x,y);
    for(int i=20;i>=0;i--) if(depth[up[x][i]]>=depth[y]) x=up[x][i]; 
    if(x==y)    return x;
    for(int i=20;i>=0;i--) if(up[x][i]!=up[y][i]) x=up[x][i],y=up[y][i];
    return up[x][0];
}
int main()
{
    read(n); read(m); read(k);
    for(int i=1;i<=m;i++)   read(e[i].from),read(e[i].to),read(e[i].val);
    Kruskal();  dfs(2*n-1,0);//注意是從2*n-1開始dfs
    for(int i=1,x,y;i<=k;i++)
    {
        read(x); read(y);
        cout<<val[lca(x,y)]<<'\n';
    }
    return 0;
}