【算法】
【实现】
主要有路径压缩和按秩合并两个优化,有论文证明了不使用按秩合并只用路径压缩的时间复杂度平均也是,但如果只用按秩合并不加路径压缩复杂度就是
了,在可持久化的时候一般使用只启发式合并的并查集
//路径压缩
int find(int x)
{
if (x != fa[x]) // x 不是自身的父亲,即 x 不是该集合的代表
fa[x] = find(fa[x]); // 查找 x 的祖先直到找到代表,于是顺手路径压缩
return fa[x];
}
//按秩合并
void union(int x, int y)
{
int xx = find(x), yy = find(y);
if (xx == yy) return;
if (size[xx] > size[yy]) // 保证小的合到大的里
swap(xx, yy);
fa[xx] = yy;
size[yy] += size[xx];
}
【题型】
1.调整顺序后运用并查集
先处理相等的,利用并查集合为一体,然后判断不等条件,如果有条件不等号两边变量在同一整体里,那么就不合法
注意还需要离散化一下
倒序处理摧毁即可
2.其他巧妙构造
这道题目要我们先转换为图论的问题,将一个装备的两个属性值连起来,如果一个连通块是一棵树那么这个连通块内的最大值就无法取到,如果连通块内有环,那么这个连通块的所有点都能取到
看了题解的代码实现非常简介,学到了!代码
3.种类(权值)并查集
在同个种类的并查集中合并,和原始的并查集没什么区别,仍然表达
他们是朋友
这个含义。考虑在不同种类的并查集中合并的意义,其实就表达
他们是敌人
这个含义了。按照并查集美妙的
传递性
,我们就能具体知道某两个元素到底是敌人
还是朋友
了。
这道题目运用了反集的思想,如果a和b是敌人,合并n+b和a,n+a和b,如果c和a是敌人,合并n+c和a,n+a和c,那么b和c就并在一起了,这样就符合了题目敌人的敌人是朋友的规则。注意这里就不能加上按秩合并的优化了,因为要保证最后的祖先是1-n里面的人 代码
这道题目要建立三个种类A,B,C,利用并查集维护它们之间的捕食关系,思维难度较大,详见这个题解,十分详细,代码