Files
python/TangDou/DisjointSetUnion/并查集.txt

57 lines
3.2 KiB
Plaintext
Raw Normal View History

2025-08-30 18:35:01 +08:00
论述并查集的文章[经典]
https://www.cnblogs.com/zhxmdefj/p/11117791.html
一、并查集
(1)hdu1232 城镇交通
[https://www.luogu.com.cn/problem/P1536] 是同一个题
知识点: 并查集初始化,递归查询并压缩路径,并查集合并,计算最终有多少个并查集等知识点,别忘了集合数量减1是答案。
(2)poj1611 感染的学生
知识点:
.需要记录每个集合中的元素个数,如果两个集合合并,还需要同时修改最终集合的个数值。
.注意初始化时也需要将每个集合的初始值设置为1
.知道了按秩合并并不是必须要学习的,因为按路径压缩的方法也是一样可以保持集合元素个数的。按秩合并代码较长,不方便记忆,OI一般不考。
.如果使用递归可能会造成爆栈,可以使用循环的方式进行替换递归的方法,但似乎用的不多。
.递归压缩路径是在查询时进行的,按秩合并是在合并时将小树加到大树中。
二、带权并查集
.每个节点都记录的是与父节点之间的权值,那么在Find的路径压缩过程中,权值也应该做相应的更新,因为在路径压缩之前,
每个节点都是与其父节点链接着,那个Value自然也是与其父节点之间的权值
向量偏移法
路径压缩
int FindSet(int x) {
if (x == parent[x]) return x;
else {
int t = parent[x]; //记录原父节点编号
parent[x] = FindSet(parent[x]); //父节点变为根节点,此时value[x]=父节点到根节点的权值
value[x] += value[t]; //当前节点的权值加上原本父节点的权值
return parent[x]
}
}
黄海解读:其实这个FindSet因为是递归,所以肯定执行多次,也就是说value[x]是要被叠加多次,比如 C->B->A三个元素 权值为1,2,
表示C到B的权值是1,B到A的权值是2。现在进行FindSet,就是查询C的祖先了,那么C就会被执行一次FindSet(C),找到了B,B也需要执行
一次FindSet(B)找到了A,A也需要执行一次FindSet(A),发现结果是自己,开始回复B,B知道了自己的祖先是A,修改自己的祖先,然后告诉
了C,C修改了自己的祖先。
其实,在上面的递归过程中,权值也会一并变化,将上面的修改一下:
.在两个并查集做合并的时候,权值也要做相应的更新,因为两个并查集的根节点不同
int xRoot = FindSet(x);
int yRoot = FindSet(y);
if (xRoot != yRoot){
parent[xRoot] = yRoot;
value[xRoot] = value[y] + s - value[x];
}
不懂看图:https://img2018.cnblogs.com/blog/1536438/201907/1536438-20190701134930241-1566925104.png
(1) hdu3038
.权值的变化方法
parent[xRoot] = yRoot;
value[xRoot] = value[y] + s - value[x];
.由于是区间和,需要有一点技巧,就是开闭区间,一般采用l--,然后左开右闭的方法
阅读材料:
https://blog.csdn.net/qq_43591839/article/details/101348031
https://blog.csdn.net/niushuai666/article/details/6981689