Kruskal 重构树
(没有查阅任何资料,没有任何提前准备,想到哪里写到哪里,代码也是现写的)
是一棵二叉树,一张 \(N\) 个点的无向连通图的 Kruskal 重构树有 \(2N-1\) 个节点。
叶子节点为原图中节点,非叶子节点有点权,表示想在原图上从一边的子树内的叶子节点所对应的原图上节点走到另一边的子树内的叶子节点所对应的原图上节点所需经过的最长边的最小可能值。
建树方式:Kruskal 每次合并 \(2\) 个节点时,新开一个点,记作这 \(2\) 个节点的重构树父亲(及并查集父亲),权值为当前这条边的权值。
代码如下:
(花15分钟敲完的模板题 [NOIP2013 提高组] 货车运输)
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+50;
int N,M;
struct Edge1
{
int x,y,Len;
}E[MAXN];
struct Edge2
{
int x,y,Next;
}e[MAXN<<1];
int elast[MAXN],tot;
void Add(int x,int y)
{
tot++;
e[tot].x=x;
e[tot].y=y;
e[tot].Next=elast[x];
elast[x]=tot;
}
bool cmp(Edge1 a,Edge1 b)
{
return a.Len<b.Len;
}
int father[MAXN];
int getfather(int x)
{
if(x!=father[x])
father[x]=getfather(father[x]);
return father[x];
}
int f[MAXN][20],depth[MAXN];
int Val[MAXN];
void Kruskal()
{
for(int i=1;i<=2*N-1;i++)
{
father[i]=i;
}
sort(E+1,E+M+1,cmp);
for(int i=1;i<=M;i++)
{
int fx=getfather(E[i].x),fy=getfather(E[i].y);
if(fx!=fy)
{
N++;
father[fx]=N;
father[fy]=N;
Add(N,fx);
Add(N,fy);
Val[N]=E[i].Len;
}
}
}
void dfs(int u,int fa)
{
depth[u]=depth[fa]+1;
f[u][0]=fa;
for(int i=1;f[f[u][i-1]][i-1];i++)
{
f[u][i]=f[f[u][i-1]][i-1];
}
for(int i=elast[u];i;i=e[i].Next)
{
int v=e[i].y;
if(v==fa)
continue;
dfs(v,u);
}
}
int GetLca(int x,int y)
{
if(depth[x]<depth[y])
swap(x,y);
for(int i=19;i>=0;i--)
{
if(depth[f[x][i]]>=depth[y])
{
x=f[x][i];
}
}
if(x==y)
return x;
for(int i=19;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int main()
{
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++)
{
scanf("%d%d%d",&E[i].x,&E[i].y,&E[i].Len);
E[i].Len=-E[i].Len;
}
Kruskal();
for(int i=N;i>=1;i--)
{
if(depth[i]==0)
dfs(i,0);
}
int Q;
scanf("%d",&Q);
while(Q--)
{
int x,y;
scanf("%d%d",&x,&y);
int Lca=GetLca(x,y);
if(Lca==0)
puts("-1");
else
printf("%d\n",-Val[Lca]);
}
}
注意到由于此题是求最大生成树,所以在输入时将边权取反,就变成了最小生成树。
都变成一棵树了,自然想怎么搞事就怎么搞事。既然 LCT 可以维护最小生成树,所以 LCT 维护 Kruksal 重构树应该也是可以的罢?
Kruskal 重构树满足父亲节点的权值不小于其子节点,所以在树上倍增这样的操作也是很常见的。
标签:重构,原图,int,Kruskal,--,节点 来源: https://www.cnblogs.com/0htoAi/p/16629734.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。