带权并查集 模板 HDU - 3038
https://vjudge.net/problem/HDU-3038
TT 写一串数字,对 FF 不可见
FF 选择一个区间(会重复操作), TT 把这个区间的和告诉 FF,然后,一些和是不正确的,所以,有一些答案是矛盾的,根据这些矛盾求出答案错误的个数。
注意两点:1、TT 给的一个 和 是正确的,如果它与之前给的 和 不矛盾。
2、FF 发现一个与之前矛盾的 和 之后,该 和 不再参与之后的分析,直接被抛弃了。
题意:给出区间[1,n],下面有m组数据,l r v区间[l,r]之和为v,每输入一组数据,判断此组条件是否与前面冲突 ,最后输出与前面冲突的数据的个数.
比如 [1 5]区间和为100 然后后面给出区间[1,2]的和为 200 那肯定就是有问题的了。
博客: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); } }