“愿世间美好一如既往,不复存在。”
关联性容器
俗称为 std::set
,是常用的 std::map
类似,内部使用红黑树实现,是一种关联容器。std::set
是一个已排序集。
需要注意的是,std::set
如同一个集合,不允许出现键值相同的元素,这是与 std::map
一个本质的区别,当然,如果既需要使用 std::set
,又无法排除重复元素的影响,可以考虑使用 std::multiset
,其用法与 std::set
类似。
std::set
支持很多操作,类比于平衡树,可以在
首先定义 std::set<int>St
:
St.insert(x)
:插入键值为的元素,如果已经存在,则不执行。返回迭代器,以及插入是否成功的一个 std::pair<iterator,bool>
。St.erase(x)
:删除所有键值为的所有元素,并返回删除元素的个数。 St.erase(it)
:此时的it
是一个迭代器,并删除当前迭代器指向的元素,此时it
必须合法。St.erase(l,r)
:此时的l,r
为迭代器,并删除所有范围在内的迭代器指向的元素。 St.clear()
:清空。
std::set
提供了一些常用的迭代器:
St.begin()
指向当前std::set
的第一个元素。St.end()
指向尾端占位符的迭代器,此时迭代器为空。St.rbegin()
指向当前std::set
的最后一个合法元素。St.rend()
指向第一个元素的前一个元素,迭代器为空。
std::set
提供了一些常用的操作:
St.count(x)
:返回std::set
内键值为的元素数量。 St.find(x)
:返回键值为的迭代器,如果不存在返回 end()
。St.lower_bound(x)
返回指向首个不小于给定键的元素的迭代器。如果不存在这样的元素,返回end()
。St.upper_bound(x)
返回指向首个大于给定键的元素的迭代器。如果不存在这样的元素,返回end()
。St.empty()
返回std::set
是否为空。St.size()
返回元素个数。
颜色段均摊
起源于一道
其核心思想在于,将权值相同的区间合并为一个结点,并保存在 std::set
里面,在随机数据的区间赋值下效率较高,但如果数据不随机,无法保证复杂度正确。
但如果复杂度正确,使用 std::set
维护可以做到
存储
根据其核心思想,在区间赋值操作时,将连续相同权值的元素合并为一个结点,也就是将整个序列表示
参考实现
1 | struct Cho |
由于 std::set
强制内部有序,所以 operator
重载运算符是必要的。而至于 mutable
,是指当整个结构体处于静态变量时,其权值依然为可变量,即不受 const
影响。
基础实现
很显然的,题目数据中所给到的操作区间与我们当前已经划分的区间可能并不大同,意味着我们可能会需要拆分区间,所以需要一个分裂区间的操作,也就是将
参考实现
1 | inline auto split(int x) |
至于区间赋值,赋值之后这一段区间一定会形如
参考实现
1 | inline void assign(int l,int r,int v) |
那么,做接下来的这道题就显得犹为简单了。
题目简介
题目名称:
题目来源:
评测链接:https://codeforces.com/problemset/problem/915/E
形式化题意:给定一个长度为
数据范围:
整个询问中只有一个修改,就是对区间进行赋值,那我们可以直接用珂朵莉树维护,而对于求和,我们选择在 assign
操作的时候进行在线维护,然后统计答案即可。
AC Code
1 | // ----- Eternally question----- |
例题
珂朵莉树的实现主要突出一个暴力,不管怎么样,都直接往最暴力的思想去凑,只要数据足够随机,其复杂度就是正确的,甚至如果将珂朵莉树与朴素暴力进行平衡规划的话,甚至可以通过很多线段树与平衡树的没有经过精心构造的数据。
纵使日薄西山
题目简介
题目名称:
题目来源:
评测链接:https://codeforces.com/problemset/problem/896/C
形式化题意:给定一个长度为
- 区间加
; - 区间覆盖
; - 求区间第
小值; - 求区间
次方和对 取模。
数据强随机,随机种子为
数据范围:
这道题就是
对于区间覆盖,就是提到的 assign
操作,而对于区间加,我们想办法把区间内所有结点提出并直接维护,也就是朴素暴力,但是枚举的是 std::set
的结点。
对于区间 std::vector
或者数组然后直接 std::sort
,最后枚举 std::vector
,有一说一,确实太离谱了。
对于区间
AC Code
1 | // ----- Eternally question----- |
纵使繁花落尽
题目简介
题目名称:脑洞治疗仪
题目来源:上海省选
评测链接
评测链接
形式化题意:给定一个长度为
- 将区间
赋为 ; - 用区间
的 去填补 的 ,多余舍去,不足则从左往右填完为止。 - 查询区间
内最大的连续 段长度。
数据范围:
超这道题洛谷上
用 checkMax
即可。
用线段树写,可以考虑类似于 「序列操作」 的维护方法,但第二个操作需要用到线段树二分,时间复杂度
AC Code(珂朵莉树)
1 | // ----- Eternally question----- |
AC Code(线段树)
1 | // ----- Eternally question----- |
山无遮,海无拦
很久没有唠嗑了呢,其实珂朵莉树能做的题说少,那是少之又少,说多,却又无穷无尽,在大多数有区间重构的题中,珂朵莉树都能拿到很多分数,但一般而言都拿不满,所以,珂朵莉树的实际运用也就只有骗分这一环了,顺便也把 std::set
学了一下。
开始停课了,我也有在准备之后的课程了,之所以还在继续断断续续整
所以,即使繁花落尽,我们永不放弃。