Kruskal重构树学习笔记
引言
其实很早就学了,但是用的不多一直没有补。做题时突然,想起来了补一下。
感觉Kruskal重构树也算一种数据节构吧。为什么要单独拎出来讲呢?因为感觉博客园里这个知识点讲的都不说很清楚,大家好像都对这个知识点嗤之以鼻(?原谅我语文不好)。新开一个会好找一点。 最后无耻宣一下:数据节构专题学习笔记。
基本信息
-
性质:
在这棵树上节点u到节点v的LCA是原图u到v路径上边权最值。且如果原图连通这棵树保证为二叉树,共有 \(2N-1\) 个节点。从小到大构建时,父亲权值不小于儿子;从大到小构建时,父亲权值不大于儿子。
其实此类问题也可以用并查集按秩合并+可持久化来维护,但重构树的优点在于可以套树剖、线段树等静态树结构。
-
建树过程:
类似执行最小生成树算法(Kruskal) ,但不直接连边,而是在新图中创建节点代表这条边。具体过程:遍历每条边(u,v,w) 并维护一个并查集。如果uv不联通:新建节点。在并查集里找到u和v的根节点:ru,rv。新建节点将ru和rv合并,把根节点设为该节点。这棵树就是Kruskal重构树。 -
code
#include <bits/stdc++.h> #define int long long using namespace std; const int N=3e5*2+10; struct EDGE{int u,v,w;}edge[N];int tot=0; void addedge(int u,int v,int w){edge[++tot]={u,v,w};} bool cmp(EDGE x,EDGE y){return x.w>y.w;} int fa[N],w[N],trfa[N],dep[N],lg[N];int stfa[N][20]; int fid(int x) {if(x!=fa[x])fa[x]=fid(fa[x]);return fa[x];} void init(int n,int m) { for(int i=2;i<3e5;i++)lg[i]=lg[i/2]+1; for(int i=1;i<=n+m;i++){trfa[i]=i;fa[i]=i;} } int LCA(int u,int v) { if(dep[u]<dep[v])swap(u,v); while(dep[u]>dep[v]){int k=lg[dep[u]-dep[v]];u=stfa[u][k];} if(u==v) return u; for(int k=lg[dep[u]];k>=0;k--) if(stfa[u][k]!=stfa[v][k]){u=stfa[u][k];v=stfa[v][k];} return trfa[u]; } signed main() { ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int n,m; cin>>n>>m; init(n,m) ; for(int i=1,u,v;i<=m;i++){cin>>u>>v>>w[i]; addedge(u,v,w[i]);} //-----------建树过程----------- sort(edge+1,edge+1+m,cmp) ; for(int i=1;i<=m;i++) { int u=edge[i].u,v=edge[i].v; int fau=fid(u),fav=fid(v); if(fau==fav) continue; n++ ; w[n]=edge[i].w; trfa[fau]=trfa[fav]=fa[fau]=fa[fav]=n; } // 在重构树中加入新节点 for(int i=n;i>=1;i--) dep[i]=dep[trfa[i]]+1; for(int i=1;i<=n;i++) stfa[i][0]=trfa[i]; for(int i=1;i<=19;i++) for(int u=1;u<=n;u++) stfa[u][i]=stfa[stfa[u][i-1]][i-1]; //初始化 int Q; cin>>Q; while(Q--) { int u,v; cin>>u>>v; if(fid(u)!=fid(v)) cout<<"-1\n"; else cout<<w[LCA(u,v)]<<"\n"; // 朴素LCA } //-----------EOF----------- return 0; }高清无注释版
#include <bits/stdc++.h> #define int long long using namespace std; const int N=3e5*2+10; struct EDGE{int u,v,w;}edge[N];int tot=0; void addedge(int u,int v,int w){edge[++tot]={u,v,w};} bool cmp(EDGE x,EDGE y){return x.w>y.w;} int fa[N],w[N],trfa[N],dep[N],lg[N];int stfa[N][20]; int fid(int x) {if(x!=fa[x])fa[x]=fid(fa[x]);return fa[x];} void init(int n,int m) { for(int i=2;i<3e5;i++)lg[i]=lg[i/2]+1; for(int i=1;i<=n+m;i++){trfa[i]=i;fa[i]=i;} } int LCA(int u,int v) { if(dep[u]<dep[v])swap(u,v); while(dep[u]>dep[v]){int k=lg[dep[u]-dep[v]];u=stfa[u][k];} if(u==v) return u; for(int k=lg[dep[u]];k>=0;k--) if(stfa[u][k]!=stfa[v][k]){u=stfa[u][k];v=stfa[v][k];} return trfa[u]; } signed main() { ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int n,m; cin>>n>>m; init(n,m) ; for(int i=1,u,v;i<=m;i++){cin>>u>>v>>w[i]; addedge(u,v,w[i]);} sort(edge+1,edge+1+m,cmp) ; for(int i=1;i<=m;i++) { int u=edge[i].u,v=edge[i].v; int fau=fid(u),fav=fid(v); if(fau==fav) continue; n++ ; w[n]=edge[i].w; trfa[fau]=trfa[fav]=fa[fau]=fa[fav]=n; } for(int i=n;i>=1;i--) dep[i]=dep[trfa[i]]+1; for(int i=1;i<=n;i++) stfa[i][0]=trfa[i]; for(int i=1;i<=19;i++) for(int u=1;u<=n;u++) stfa[u][i]=stfa[stfa[u][i-1]][i-1]; int Q; cin>>Q; while(Q--) { int u,v; cin>>u>>v; if(fid(u)!=fid(v)) cout<<"-1\n"; else cout<<w[LCA(u,v)]<<"\n"; } return 0; }

浙公网安备 33010602011771号