并查集是什么
概念
并查集是个啥呀?并查集,并,查,集。合并,查找,集合。就是这样,并查集就是可以合并查找两种操作的集合。从树的角度看,并查集就是个森林,每一棵树代表一个集合。我们要干的事情就是对于一个森林集合进行合并、或者查找。
如何实现
我们如何实现判断两个元素是否在一个集合里面呢?我们知道,在同一棵树里面的所有点,都有一个共同的祖先——根结点。ok,我们只要求出两个元素的根结点, 就可以判断这两个点是否在同一个集合里了。
合并就很容易了,把其中一个根结点变成另一个根结点的孩子结点就可以了。
是不是就很容易了?
路径压缩
我们知道对于一棵树,要求一个结点的祖先,需要一层一层通过父亲结点找上去,直到那个结点没有父结点。这样需要递归很多次。查找一个元素的祖先需要的时间复杂度是O(N)。路径压缩,实际上就是在找完根结点之后,在递归回来的时候顺便把路径上元素的父亲指针都指向根结点。是记忆化的应用。这样以后,查找两个元素是不是在一个集合里时间复杂度是O(1)。
模板
我们用一个int类型的father数组来存储每一个元素的父亲结点。对于father数组的初始化是把元素father[i]初值设置为i。
查找根结点
int getfather(int v)
{
if(father[v]==v) return v;
//如果一个元素的父亲结点是自己,就说明它本身就是一个根结点
father[v]=getfather(father[v]);//路径压缩,把结点的父亲改为根结点。
return father[v];//返回值。
}
并:把两个结点并到一个集合
void un(int x,int y)
{
int fx,fy;
fx=getfather(x);
fy=getfather(y);
//找到两个结点的结点
father[fx]=fy;
//其中一个根结点变成另一个根结点的孩子。
}
查:两个元素是否在一个集合
bool judge(int x,int y)
{
int fx,fy;
fx=getfather(x);
fy=getfather(y);
return fx==fy;
//如果根结点相同,返回true,代表在同一个集合。
}
并查集就是那么简单。
例题(每一题都见链接)
luoguP3366 最小生成树
题解链接:最小生成树题解by柴犬首相
luoguP3367 并查集
题解链接:并查集模板题by柴犬首相
luoguP1551 亲戚
题解链接:亲戚题解by柴犬首相