所谓并查集,就是一种支持并与查的数据结构,是一种集合。并即为合并,查即为查询。
我们给每个集合选择一个代表元素,每个元素记录一个(fa)数组,表示它所在的集合的代表元素。合并两个集合,我们只需要将其中一个集合的代表元素的(fa)数组赋值为另外一个集合的代表元素即可。代表元素的(fa)就是自己。这样子操作的话,所有元素之间的关系就会形成一个森林,若要查询两个元素是否在同一个集合内,只需要看看他们的根是否相同即可。
但是,如果树的深度为(n),每次查询都是(O(n))的,这个复杂度是我们所不能接受的。
路径压缩
由于我们只关注每个元素所在的树的根是谁,所以我们不必将整条链谁在前谁在后记录下来,只需要将每个元素直接指向根即可。
int find(int x) {
if(fa[x]==x)return x;//自己就是树根
return fa[x]=find(fa[x]);//将自己的fa数组指向树根并且返回
}
按秩合并
所谓秩,就是树的深度或者集合大小。在秩的概念等于集合大小的时候,这又称为启发式合并。每次合并将秩较小的集合往秩较大的集合上并,这样子只会增加小的集合的元素的询问复杂度。我们只需要把每个集合的秩记录在代表元素上即可。
带边权的并查基
我们可以在树的边上记录一些信息,每次路径压缩的时候更新每个元素往自己父亲那一条边上的信息,通过一些信息的性质,我们可以计算出同一集合内任意两个元素之间存在的某些关于我记录的信息的关系,这就是带边权的并查基。
并查基是一种十分简洁明了的数据结构,操作也就只有上面几种。由于本数据结构十分简单,所以一般题目都会变着法子增加思维难度。怎么在题目中找到元素之间的关系以及如何用并查基维护我们需要知道的信息,才是我们学习并查基的重中之重。