Kruskal 重构树学习笔记
Kruskal 重构树学习笔记
参考博客
性质
这里给定最小生成树 Kruskal 重构树 的性质,那么最大生成树 Kruskal 重构树 的性质可以同理得。
重构树是一棵恰有 n 个叶子节点的完满二叉树,每个非叶子节点都有两个儿子,共有 2n−1 个点。(初始图中的 n 个点是叶子,由于是棵树,边数为 n−1 ,相当于每条边都新建了一个点,那么点数自然是 2n−1 )。
重构树的点权符合大根堆的性质。(从上到下边权递减,最上面的点边权最大,因为边权大的边后面加)。
原图中两点间所有简单路径的最大边权最小值,等于最小生成树上两点之间边权最大值,等于重构树上两点 LCA 的点权。(这下任意两点间的最小瓶颈路就只用求一个 LCA 了)。
从 u 出发,经过边权不超过 k 的边,所能到达的点恰好是重构树上某棵子树内的所有叶子节点。(可以这么想,从 u 点一直向上走,直到点权大于 k,那么那个点相当于就不能过,由于是一颗树,不能经过一个点,断开之后 u 所在部分就是一颗子树)。
模板题
P1967 [NOIP2013 提高组] 货车运输
按照从大到小排序,然后建图,然后树链剖分/倍增求一下LCA即可。
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
//开2倍空间
const int N=1e5+10;
struct node{
int u,v,w;
bool operator<(const node &u)const{
return w>u.w;
}
}edge[N];
int p[N];
int find(int x){
return p[x]==x?x:p[x]=find(p[x]);
}
int n,m,q;
vector<int> e[N];
int fa[N],dep[N],son[N],sz[N];
int top[N],tot,w[N];
//预处理各个信息
void dfs1(int u,int father){
fa[u]=father;
dep[u]=dep[father]+1;
sz[u]=1;
for(auto v:e[u]){
if(v==father) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v]) son[u]=v;
}
}
void dfs2(int u,int tp){
top[u]=tp;
if(!son[u]) return;
dfs2(son[u],tp);
for(auto v:e[u]){
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
void kruskalRT(){
sort(edge+1,edge+m+1);
for(int i=1;i<=2*n;i++) p[i]=i;
tot=n;//虚点从n+1开始建
for(int i=1;i<=m;i++){
int u=find(edge[i].u),v=find(edge[i].v);
if(u==v) continue;
p[u]=p[v]=++tot;
w[tot]=edge[i].w;
e[tot].push_back(u);
e[u].push_back(tot);
e[tot].push_back(v);
e[v].push_back(tot);
if(tot==(n<<1|1)) break;
}
}
void Showball(){
cin>>n>>m;
for(int i=1;i<=m;i++) cin>>edge[i].u>>edge[i].v>>edge[i].w;
kruskalRT();
//有可能为一个森林
for(int i=tot;i>n;i--) if(!sz[i]) dfs1(i,0);
for(int i=tot;i>n;i--) if(!top[i]) dfs2(i,i);
int q;
cin>>q;
while(q--){
int u,v;
cin>>u>>v;
if(find(u)!=find(v)) cout<<"-1\n";
else cout<<w[lca(u,v)]<<"\n";
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--){
Showball();
}
return 0;
}