带权并查集 模板 HDU - 3038

https://vjudge.net/problem/HDU-3038

TT 写一串数字,对 FF 不可见
FF 选择一个区间(会重复操作), TT 把这个区间的和告诉 FF,然后,一些和是不正确的,所以,有一些答案是矛盾的,根据这些矛盾求出答案错误的个数。
注意两点:1、TT 给的一个 和 是正确的,如果它与之前给的 和 不矛盾。
2、FF 发现一个与之前矛盾的 和 之后,该 和 不再参与之后的分析,直接被抛弃了。

博客:https://www.cnblogs.com/liyinggang/p/5327055.html

https://blog.csdn.net/yjr3426619/article/details/82315133?tdsourcetag=s_pcqq_aiomsg

首先要先知道带权路径压缩的写法:

int find(int x){
    if(pre[x]!=x){
        int y = pre[x];
        pre[x] = find(pre[x]);
        sum[x] += sum[y];
    }
    return pre[x];
}

还有带权并查集合并:

pre[fa] = fb;
sum[fa] = -sum[a] + s + sum[b] ;

这题我们利用一个sum[]数组保存从某点到其祖先节点距离。
通过处理,带权并查集每个节点的sum值都是其指向父亲节点的权值
中间如果经历过了路径压缩,就是指向祖先的权值

注意,给出区间的 L 和 R可能相同,而就无法用并查集这个数据结构来做了,所以存入时要把 L- - 或者R ++

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <algorithm>
#include <queue>
#define INF (1<<30)
using namespace std;

const int maxn = 2e5+7;
int sum[maxn];
int pre[maxn];

int find(int x){
    if(pre[x]!=x){
        int y = pre[x];
        pre[x] = find(pre[x]);
        sum[x] += sum[y];
    }
    return pre[x];
}

int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=0; i<=n+1; i++){
            pre[i] = i;
            sum[i] = 0;
        }
        int fa,fb,a,b,s,ans=0;
        while(m--){
            scanf("%d%d%d",&a,&b,&s);
            b++;
            fa = find(a);
            fb = find(b);
            if(fa==fb){
                if(sum[a]!=s+sum[b]){
                    ans++;
                }
            }
            else{
                pre[fa] = fb;
                sum[fa] = -sum[a] + s + sum[b] ;
            }
        }
        printf("%d\n", ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/-Zzz-/p/11469812.html