带权并查集学习的一些心得体会

这两天学习了一些新型的并查集,比如带权并查集,种类并查集等。
众所周知,并查集就是记录了元素和元素之间的关系,主要是归属关系,可以把一部分元素分类到其所属的集合中,而带权并查集,维护的就不只是关系了,还有元素和元素之间的权值差。如果将一个并查集类比成一张图,那么所谓带权,就是指边权或者点权。
带权并查集学习的一些心得体会_第1张图片
这是一个简略的带权并查集,1就是这个集合的头,带圈的数字就是元素,其他数字就是对应的权值,将其转化为点权的话,就是val[1]=0,val[2]=1,val[3]=1,val[4]=2,有点像前缀和的感觉。
那么这种并查集有什么用的,很显著的一个特点,这种并查集可以存下元素和元素之间的相对关系,而原先的并查集只能储存归属关系。来一道例题帮助一下理解吧。

HDU-3038-How Many Answers Are Wrong
有M个数,不知道它们具体的值,但是知道某两个数之间(包括这两个数)的所有数之和,现在给出N个这样的区间和信息,需要判断有多少个这样的区间和与前边已知的区间和存在矛盾。例如给出区间和[1,4]为20,[3,4]为15,再给出[1,2]为30,显然这个[1,2]的值就有问题,它应该为20-15=5。
如果用带权并查集来做这道题,首先,我们知道,带权并查集是储存了一个并查集中元素之间的相对关系,那么我们就可以利用这些元素之间的相对关系得到这个集合中任意两个元素之间的关系,类比到这道题中,就是查询的区间是否冲突。如果查询的区间是在一个集合中的,那么我们就可以知道这个区间的相对差值,如果和给的值不同,自然就是冲突的。

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define pb push_back
#define mk make_pair
#define rep(a,b,c) for(int a=b;a
#define repp(a,b,c) for(int a=b;a<=c;a++)
#define mem(a,b) memset(a,b,sizeof(a))
const int inf=0x3f3f3f3f;
void useiostream()
{
   
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
const int maxn=200005;
int root[maxn];
int val[maxn];
int find(int num)
{
   
	if(root[num]!=num)
	{
   
		int i=root[num];
		root[num]=find(root[num]);
		val[num]+=val[i];
	}
	return root[num];
}
int main()
{
   
	useiostream();
	int n,m;
	while

你可能感兴趣的:(并查集)