【带(加)权并查集】算法学习


带(加)权并查集思想:

相比于简单的并查集,带权并查集中各个节点之间的关系更为复杂。


带(加)权并查集实现:

带(加)权并查集的实现同简单并查集并没有什么不用,但是带(加)权并查集的关系合并操作中会比多用到模除或者是异或操作,具体因题而异。


例题:

题目地址:食物链 POJ - 1182

解析:
本题作为带(加)权并查集经典题目,代码中的合并操作在主函数中完成了。而且通过向量思维的解释,该题的逻辑也更容易理解。
向量思维:
1.若rootx与rooty不同,则:
rootx->rooty = rootx->x + x->y + y->rooty
即rootx->rooty = (relation[x]+d-1+3-relation[y])%3 = relation[rooty]
2.如果rootx和rooty相同,则:
x->y = x->rootx + rootx->y
即x->y = (3-relation[x]+relation[y])%3

下面直接上代码:

#include <iostream>
#include <cstdio>

using namespace std;

const int N=50000;
struct Node{
    int fa; //父节点
    int re; //与父节点的关系,0为同类,1为被父节点吃,2为吃父节点
} ani[N+5];
int n,k;

void UFInit()
{
    for(int i=1;i<=n;i++)
    {
        ani[i].fa=i;
        ani[i].re=0;
    }
}

int Find(int a)
{
    if(ani[a].fa==a)
        return a;

    int tem=ani[a].fa;
    ani[a].fa=Find(tem);    //路径压缩
    ani[a].re=(ani[a].re+ani[tem].re)%3;    //穷举法推出
    //子与爷的关系通过子与父和父与爷推出,故需中间变量保存父
    return ani[a].fa;
}

int main()
{
    int d,x,y,ans=0;

    scanf("%d%d",&n,&k);
    UFInit();

    while(k--)
    {
        scanf("%d%d%d",&d,&x,&y);

        if(x>n||y>n)    //条件二
        {
            ans++;
            continue;
        }

        if(d==2&&x==y)  //条件三
        {
            ans++;
            continue;
        }

        int rootx=Find(x);
        int rooty=Find(y);

        //向量法中,ani[x].re表示rootx~x
        //根据ani[x].re可反向推出x~rootx的关系,即(3-ani[x].re)
        if(rootx!=rooty)    //合并
        {
            ani[rooty].fa=rootx;
            ani[rooty].re=(ani[x].re+(d-1)+(3-ani[y].re))%3;
            //向量法,rootx~rooty=(rootx~x + x~y + y~rooty)%3
        }

        else
        {
            if(d==1&&ani[x].re!=ani[y].re)
                ans++;

            else if(d==2&&((3-ani[x].re)+ani[y].re)%3!=d-1)
                //向量法,x~y=(x~rootx + rooty~y)%3
                ans++;
        }
    }

    printf("%d\n",ans);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值