oistr
2020-02-21 22:33:10
此文章中所有图片均为作者本人所绘,所有代码均经作者本人编写,运行通过。如需转载,请联系作者(LG 私信即可)
如有错漏之处,敬请各位奆佬指正!
这是个比较冷门的数据结构。。。(其实很简单而且并不冷门)
我是在做 P1892 [BOI2003]团伙的时候听说的。
那么,我就来讲解一下这个结构。
upd at 2020-09-17 准备开始扩写这篇文章
所以我说他很菜嘛...
咱们做并查集的问题,基本上题面都是这样“三步走”:
当然第三步可能会有一些变更,例如
这些都可以通过一些小优化在
假如在第二步上做一些变更呢?
给定两种关系。第一种:给定一对朋友关系;第二种,给定一对敌人关系,满足敌人的敌人就是朋友。
那么传统并查集就捉襟见肘了。
我们当然可以使用暴力方法(Floyd)在
其实有一种方法能在
反集的思路是再构造一个集合(称之为反集),然后将“敌人”关系通过原集和反集表示出来。
比如假设有
那么,如何体现敌人关系呢?
假如有一对敌人关系
我们只需要连接两条边
这样,在
等等!还有一个敌人的敌人就是朋友关系,在这里是否是正确的呢?
假如还有一对敌人关系
我们按照上面的规则,连接
则图变成了两个连通块(如下图,红色,蓝色)。
好像脱氧核糖核酸啊。。。
自然地,
在代码中,我们可以开
代码只需要在并查集的基础上加两个部分即可。
定义:
for(int i=1;i<=2*n;i++)//注意这里的2*n。
{
r[i]=i;
}
读入结点u,v之间的关系;
if(朋友关系)
{
union(u,v);
}
else//敌人关系。
{
//刚刚讲过的操作。
union(u,v+n);
union(v,u+n);
}
反集虽然不是一个特别常见的数据结构,但是在并查集的优化中很有用。希望这篇文章对你有帮助。有什么不理解的都可以在评论区问哦~