You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

57 lines
3.1 KiB

2 years ago
论述并查集的文章[经典]
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的权值是1B到A的权值是2。现在进行FindSet就是查询C的祖先了那么C就会被执行一次FindSet(C),找到了BB也需要执行
一次FindSet(B)找到了AA也需要执行一次FindSet(A)发现结果是自己开始回复BB知道了自己的祖先是A修改自己的祖先然后告诉
了CC修改了自己的祖先。
其实,在上面的递归过程中,权值也会一并变化,将上面的修改一下:
.在两个并查集做合并的时候,权值也要做相应的更新,因为两个并查集的根节点不同
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