前言科技改变生活
本来一直被畏于巨长的声明,没有学这个东西…
直到 棘手的操作 这道题,pb_ds模拟实现的两个log的做法不仅好写的一批,连时间竟然也把我单log的左偏树爆踩了???
…
我选择打不过就加入…
注意:本文一切服从于OI的实用性,可能会舍弃一些在OI领域对于我个人用处不大的功能。
哈希表的功能我选择舍弃了,因为哈希表本身并不是难于编写的结构。
auto 非常方便。
(可能会动态更新?)
头文件pb_ds一族的万能头:
#include
就是把普通万能头的 std 改成了 ext (extend)。
堆 总结pbds的堆与stl相比,额外支持的函数如下:
宏定义&声明
- join(__gnu_pbds :: priority_queue &other): 把 other 合并到 *this 并把 other 清空。
- erase(point_iterator): 把迭代器位置的键值从堆中擦除。
- modify(point_iterator, const key): 把迭代器位置的 key 修改为传入的 key,并对底层储存结构进行排序。
(这里的宏定义只是笔者个人的习惯,下文会默认使用。)
namespace pd = __gnu_pbds; #define It pd::priority_queue::point_iterator pd::priority_queue q;
其中 point_operator 是 pb_ds 族所使用的迭代器。
cmp 是自定义的小于号,默认为 less
struct cmp{
bool operator ()(const int &x,const int &y){return xq;
实际上比较符之后还有两栏可以自定义,但在OI应用中几乎都是默认即可(默认的堆实现方式是配对堆)。
成员函数(完全复制 OI-wiki )
复杂度
- push(): 向堆中压入一个元素,返回该元素位置的迭代器。
- pop(): 将堆顶元素弹出。
- top(): 返回堆顶元素。
- size() 返回元素个数。
- empty() 返回是否非空。
- modify(point_iterator, const key): 把迭代器位置的 key 修改为传入的 key,并对底层储存结构进行排序,返回该元素位置的迭代器。
- erase(point_iterator): 把迭代器位置的键值从堆中擦除,返回值为 void。
- join(__gnu_pbds :: priority_queue &other): 把 other 合并到 *this 并把 other 清空。
push 和 join 是 O ( 1 ) O(1) O(1),其余均为最差 O ( n ) O(n) O(n),均摊 O ( log n ) O(log n) O(logn)。
迭代器失效 点失效保证与stl不同,pbds的迭代器非常强大。
只要迭代器没被删除,就始终保持有效。
即使执行过 modify 操作都是有效的!
点迭代器被删除,访问时依然不会RE,而是会返回0。
但是如果开启 -fsanitize=address,就会出现报错 heap-use-after-free。
点迭代器被删除,再将其作为某个函数的参数传入时(如 modify erase),会直接RE。
平衡树 总结优势:查询排名和k大。
似乎还有一些更加神奇的操作?但是经过 维持记忆开销和获得效果之间的性价比 权衡后,我并不想get了…
声明注意:pbds的tree必须是不可重集合!否则不仅会吞掉重复元素,在合并两棵树的时候还会发生不可预知的错误。具体实现上,可以使用 double 或者 pair 来解决该问题(个人更倾向于后者)。
pd::treeq;
key:排序所用的键值类型。
mapped:映射类型。如果写成 null_type 则是无映射类型,相当于 std::set,否则就有些类似 std::map。
pd::rb_tree_tag :底层使用红黑树的实现,看OIwiki和于季平的课件各项指标都不错,就背这一个吧。
pd::tree_order_statistics_node_update:统计更新树的节点排名,没有它就没法支持查排名和k大!所以必须用…(首字母记忆:脱欧是内忧)
- insert(key):向树中插入一个元素 x(若为map则是pair),返回 std::pair
。 - erase(key/iterator):从树中删除一个元素/迭代器 x,返回一个 bool 表明是否删除成功。
- order_of_key(key):返回 x 以 cmp 比较的排名(unsigned long)。(排名)
- find_by_order(int):返回 cmp 比较的排名所对应元素的迭代器。(k大)
- lower_bound(key):以 cmp 比较做 lower_bound,返回迭代器。
- upper_bound(key):以 cmp 比较做 upper_bound,返回迭代器。
- join(tree):将 x 树并入当前树,前提是两棵树的类型一样,x 树被删除。
- split(x(key),b(tree)):先清空 b 树,再以 cmp 比较,小于等于 x 的属于当前树,其余的属于 b 树。
- empty():返回是否为空。
- size():返回大小。
这里的“排名”是指大于该元素的元素个数。



