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;
}