【算法】并查集

文章介绍了并查集的基本操作,包括查找和合并,并扩展到带权并查集的概念,其中涉及路径压缩和权值计算。通过一个具体的例题——HDU3038,展示了如何利用带权并查集解决寻找序列中错误查询答案的问题,主要思路是通过合并集合并检查权值是否匹配来找出矛盾的查询。
摘要由CSDN通过智能技术生成

并查集基础:

查找、路径压缩、合并

int fa[maxn];
int find(int x){
	if(fa[x] == x) return x;
    else return fa[x] = find(fa[x]);
}

void union(int x, int y){
    fa[find(x)] = find(y);
}

带权并查集:

查找+路径压缩:

递归向上查找父亲,向下计算权值

int find(int x){
    if(fa[x] == x) return x;
    else{
        int tmp = fa[x];
        fa[x] = find(fa[x]);
        val[x] += val[tmp];
        return fa[x];
    }
}

合并:

// x, y 之间建立权为d的父亲边
fx = find(x);
fy = find(y);
if(fx != fy){
    fa[fx] = fy;
    val[fx] = -val[x] + val[y] + d;
}
// 验证 x,y 之间的权值是否为 d
else{
    if(val[x] - val[y] != d){
        cnt++; // 不符合要求的个数
    }
}

例题:

经典带权并查集:HDU3038

题目大意:

现给出n个数字组成的序列,编号为1~n;
给出m个查询,每个查询的答案由a,b,s三个数组成,表示从第a个数加到第b个数的和为s;
但是其中有一些是有矛盾的(或者说错误的),求错误的查询答案有多少个。

pCqFleU.jpg

if(sum[A] - sum[C] != val) cnt++;

A、B 与 C、D 两个集合连接起来,即合并

pCqFUQx.jpg

fa[D] = B;
sum[D]=sum[A]+val-sum[C];

AC代码:

#include<bits/stdc++.h>
#define ll long long
#define db double
#define PII pair<int, int>
using namespace std;

const ll maxn = 2e5 + 10;

int fa[maxn], sum[maxn];

int find(int i){
    if(fa[i] == i) return i;
    int tmp = fa[i];
    fa[i] = find(fa[i]);
    sum[i] += sum[tmp]; // 路径压缩,并且需要所有上面节点的值,与普通并查集不一样的点
    return fa[i];
}

int main(){
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF){
        int ans = 0;
        for(int i = 0; i <= n; i++){
            fa[i] = i;
            sum[i] = 0;
        }
        for(int i = 0; i < m; i++){
            int a, b, s;
            scanf("%d%d%d", &a, &b, &s);
            a--;
            int aa = find(a);
            int bb = find(b);
            if(aa != bb){
                fa[bb] = aa;
                sum[bb] = sum[a] + s - sum[b];
            }
            else{
                if(sum[b] - sum[a] != s) ans++;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值