cp数据结构
数据结构
并查集
功能
并查集维护了一些不相交的集合,支持两种操作:
- 查询(Find):查询两个元素是否在同一个集合中。
- 合并(Union):把两个不相交的集合合并为一个集合。
初始化
并查集的结构是一个森林,其中每棵树表示一个集合,根节点作为集合的代表元素。
每个节点只存储它的父节点,根节点的父节点指向自己。
1 | digraph G { |
1 | struct dsu { |
合并
只需要将一个集合的根节点指向另一个集合的根节点即可。
合并 1 号节点的集合和 2 号节点的集合:
1 | digraph G { |
合并 1 号节点的集合和 3 号节点的集合:
1 | digraph G { |
启发式合并
我们可以将节点较少或深度较小的树(通常是节点数较少的树)连到另一棵树上, 避免树退化成链。
按秩合并:
1 | bool unite(int x, int y) { |
查询
查询两个元素是否在同一个集合中,只需要看它们的根节点是否相同即可。
路径压缩
查询过程中遇到的节点可以直接指向根节点,方便后续查询。
例如在下面的并查集中查询 4 号节点
1 | digraph G { |
把经过的 1 2 4 号节点直接接在 3 号节点上
1 | digraph G { |
路径压缩会在一次查询中改变多个节点, 因此在可持久化并查集等修改代价较高的情况下通常只使用按秩合并。
删除 & 移动
为了保证删除节点时不会影响到其他节点,我们只能删除叶子节点。
我们可以预先为每个节点分配一个虚拟节点作为父亲。
这样就可以保证所有实际的节点都是叶节点,删除或移动时直接修改即可。
完整代码
1 | struct dsu { |
时间复杂度
- 按秩合并与路径压缩都没有:最坏
- 只有按秩合并:
- 只有路径压缩:平均
,最坏 - 路径压缩 + 启发式合并:
例题
P3367【模板】并查集
模版题
P1197【JSOI2008】星球大战
给定一张图,依次删除一些点,求每次删除后的联通块数量。
离线,求出最终的状态,将删除的节点按相反顺序依次加入图中,并查集维护联通块数量。
P2024【NOI2001】食物链
有三类动物
现有
有人用两种说法对这
- 第一种说法是
1 X Y,表示和 是同类。 - 第二种说法是
2 X Y,表示吃 。
依次给出
输出假话的总数。
做法 1
对每种动物建 3 个点,表示它自己、它的天敌、它的猎物。
对于“
对于“
如果两个动物已经有关系并且和给定的描述矛盾,则说明是假话。
做法 2
使用带边权的并查集,边权为两个动物的关系。
资料
https://zhuanlan.zhihu.com/p/93647900
单调队列
功能
单调队列实现了这样的功能:
- 像普通队列一样入队、出队。
- 查询队列内元素的最大值(或最小值)。
例题
P1886 滑动窗口 /【模板】单调队列
有一个长为
资料
https://oi-wiki.org/ds/monotonous-queue/
st 表
P3865 【模板】ST 表 && RMQ 问题
板子题
P3793 由乃救爷爷
板子题(静态数组多次询问区间最大值),但数据范围大一点
分块,每块大小
块间查询拆成 后缀+整块+前缀,复杂度
块内暴力,复杂度
可以使用位运算优化块内查询:
对于区间
对于每个