简介
pb_ds 全称为 Policy-Based Data Structures,里面定义了很多比 STL 更实用的数据结构,直接好处就是比如你要用一个 Treap 去维护某些数据,本来要写几十行的 Treap,现在只用几行代码就可以定义一个这样的结构出来。
使用 pb_ds 需要的头文件以及一些命名空间的申明:
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#define ext __gnu_pbds
using namespace ext;
或者可以直接:
#include <bits/extc++.h>
这样后面的数据结构需要的额外头文件都可以不用管了。
Hash表
有两种 hash表的写法:
ext::cc_hash_table<int,bool> h1; // 拉链法
ext::gp_hash_table<int,bool> h2; // 探查法
都重载了 [] 运算符,速度跟 unordered_map 可能差不多。
Heap
和标准 STL 一样也是 priority_queue
,不过它有很多种实现方式,也就是可以通过不同的标签(tag)指定不同的实现方式。使用 pb_ds 的 priority_queue 需要包含头文件:
#include <ext/pb_ds/priority_queue.hpp>
定义方式为:
priority_queue<type,cmp=std::less<type>,tag=pairing_heap_tag>
具体来说有如下几种tag:
ext::priority_queue<int,greater<int> > que1; // (默认为配对堆)
ext::priority_queue<int,greater<int>,pairing_heap_tag> que2; // 配对堆(应该是最快的)
ext::priority_queue<int,greater<int>,binary_heap_tag> que3; // 二叉堆
ext::priority_queue<int,greater<int>,binomial_heap_tag> que4; // 二项堆
ext::priority_queue<int,greater<int>,rc_binomial_heap_tag> que5;//
ext::priority_queue<int,greater<int>,thin_heap_tag> que6; // 斐波那契堆
pb_ds 的 priority_queue 的基本操作例如 pop
、push
、top
、size
等等和 STL 的是一样的,所以一般情况下用 STL 的 priority_queue 就足够了,但是 pb_ds 的有一个操作非常好,就是 que.join(priority_queue &q)
,该操作可以合并两个堆,并且把被合并的堆清空,这就完美地解决了可并堆的问题。
Tree
这个是我认为目前来说 pb_ds 最有用的地方了,总是会有需要维护一堆数据,然后查询其中排名啊什么的,这个用 Treap(或者类似的 Splay 树)当然可以解决,但是 pb_ds 已经帮我们实现了红黑树,并且支持查询排名等等扩展功能。
需要的额外头文件:
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>
定义方法:
tree<type,null_type,cmp,tag,update>
不过一般只会用到这个:
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> oset;
其中 tag 其实还有其他的实现方式(例如splay等等),但是据 codeforces 这篇博客说的其它实现方式的某些操作是线性复杂度的,所以最好就用红黑树了。这个 oset 的基本操作和 STL 的 set 一样,但是它支持下面两个有用的操作:
oset.find_by_order(x) // 返回一个迭代器,指向排名为x(从0开始)的元素
oset.order_of_key(x) // 返回严格小于x的元素数目,也就是x的排名(从0开始)
尽管非常有用,但是它和 set 一样,不能处理重复元素,所以手写 Treap 还是有用的。