算法笔记——并查集

一、扩展域并查集

适用情况:涉及到2种或3种相互关系冲突判断时使用。

例如划分两个集合,有互斥关系的人不在一个集合,有友好关系的人得在同一个集合,判断能不能划分成满足要求不冲突的两个集合。

具体操作:将并查集扩大一倍,x表示本身,x+n表示冲突的反节点。表示友好关系时,x和y以及x+n和y+n合并;表示互斥关系时,x+n和y以及y+n和x合并。

进行冲突判断时,如果表述为友好,但x+n和y(或x和y+n)已经在同一集合,则冲突;

如果表述为互斥,但x+y(或x+n和y+n)已经在同一集合,则冲突。

二、加权并查集

对边添加权值,对节点设置数组d[i]表示i节点到树根的权值总和(即到树根距离)。在路径压缩时向上搜索到树根后向下更新d[i];合并时调整将要成为儿子的元祖节点的d值,使更改后两子树中节点的相对深度不变。

更新操作:

int find(int x)
{
    if(fa[x]==x) return x;
    int fx=fa[x];//保存父节点,只加父节点的d值
    fa[x]=find(fa[x]);
    d[x]+=d[fx];//更新d值
    // d[x]%=mod  有时需要取模
    return fa[x];
}

合并操作:

void join(int x,int y,int w)//w为x,y相对距离
{
    int fx=find(x),fy=find(y);
    if(fx==fy) return;
    fa[fy]=fx;
    d[fy]=(d[x]-d[y]-w+Mod)%Mod;
}

更改被合并的儿子节点d[fy]使x,y的相对距离w不变

因为以fx为根,则x到根距离不变,y到根距离为d[fy]+d[y]

d[x]-(d[fy]+d[y])\equiv w  ,推导得d[fy]\equiv d[x]-d[y]-w

三、启发式合并

可以增加一个树高h数组,将深度小的树合并到深度大的树下,合并后大树深度不变;若两树深度相同,合并后深度+1

int join(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx==fy) return;
    if(h[fx]>h[fy]) fa[fy]=fx;
    else fa[fx]=fy;
    if(h[fx]==h[fy]) h[fy]++;//因为相等的情况是合并到fy的
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值