从pbds、rope到stl数据结构的奇技淫巧
1. pbds
-
pbds常用的有哈希表,平衡树,以及各种堆等数据结构。
-
首先使用pbds都要加上**
using namespace __gnu_pbds;
** -
哈希表
-
#include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/hash_policy.hpp>
-
使用方法
-
定义:
cc_hash_table<int, bool> hash1; //拉链法处理冲突 gp_hash_table<int, bool> hash2; //探测法处理冲突(较快)
-
使用
- 直接hash1[a]=x,类似map。
- 使用hash1.find(a),查找一个键值。
-
-
-
平衡树
-
#include <ext/pb_ds/tree_policy.hpp> #include <ext/pb_ds/assoc_container.hpp>
-
使用方法
-
定义:
tree<nod, null_type, less<nod>, rb_tree_tag, tree_order_statistics_node_update> t;//第二维有可能是null_mapped_type(老版本)
-
rb_tree_tag一维可选其他的,但都太慢了。
-
会去重!
-
迭代器可以–
-
使用
.insert(一个元素)
.erase(一个元素)
.order_of_key(一个元素) //求k在树中是第几大
.find_by_order(一个数)//查第几大是谁
.lower_bound() .upper_bound()
.join(另一个树)//要求元素值区间不相交,全大或全小
.split(v,b)key小于等于v的元素属于a,其余的属于b
-
-
高能使用
-
自定义类来实现求前缀和之类的操作。
-
tree_order_statistics_node_update这一维是可以自定义结构体的。
-
首先必须的结构是
template<class Node_CItr,class Node_Itr,class Cmp_Fn,class _alloc> struct my_node_update { virtual Node_CItr node_begin() const =0; virtual Node_CItr node_end() const =0; typedef int metadata_type; };
-
在这个struct里面要做的就是我们想做的事情啦,添加一些和结点相关的数据,即插入的时候有一个含有数据的第二维,相当于插入的数据是一个结构体。
-
首先肯定要定义一个合并左结点和右节点信息的函数,以下为一个例子。
void operator()(Node_Itr it, Node_CItr end_it) { Node_Itr l=it.get_l_child(); Node_Itr r=it.get_r_child(); int left=0,right=0; if(l!=end_it) left=l.get_metadata(); if(r!=end_it) right=r.get_metadata(); const_cast<int&> (it.get_metadata())=left+right+(*it)->val; }
-
可以在函数内部自定义一些方法,如下,相当于在平衡树上二分。
int prefix_sum(int x) { int ans=0; Node_CItr it=node_begin(); while(it!=node_end()) { Node_CItr l=it.get_l_child(),r=it.get_r_child(); if(Cmp_Fn()(x,(*it)->first)) it=l; else { ans+=(*it)->second; if(l!=node_end()) ans+=l.get_metadata(); it=r; } } return ans; }
-
在内部主要使用的函数就是.get_l_child() .get_r_child() .get_metadata()
-
自己定义的时候就可以改为
tree<nod, null_type, less<nod>, rb_tree_tag, my_node_update> t;
-
太nb了!
-
-
-
堆
-
#include<ext/pb_ds/priority_queue.hpp>
-
使用
-
定义
__gnu_pbds ::priority_queue<nod, less<nod>, pairing_heap_tag> a;//要加命名空间防冲突
-
第一维定义数据类型,第二维greater是大根堆,less是小根堆,第三维选择堆的类型。
-
堆的类型的选择
- 使用合并的时候使用 pairing_heap_tag
- 做dijisktra的时候使用 thin_heap_tag
-
用法
.push(一个元素) .pop() .top() .empty() .clear()
.modify(一个迭代器,一个值)
.erase(一个迭代器)
.join(另外一个堆)//最nb的功能!
.split(Pred prd,priority_queue &other)//分成两个堆,在树里可能比较好用
-
-
2. rope
- 首先要带头文件
#include<ext/rope>
- 使用rope还需要带命名空间
using namespace __gnu_cxx;
- 定义方法
rope<变量类型>变量名称
- 复杂度基本都为 l o g log log级别,据说 1 0 6 10^6 106的字符串只需要不到 1 M B 1MB 1MB的空间!
- 用法
- 在字符串和整数类型的存储应用较广,在此只讲这两种。
- 插入s的前n位:
insert(int 起始位置, string &s/int *a, int 长度)
- 向末尾插入s的pos开始的n位:
append(string &s/int *a,int 串s的起始位置,int 长度)
- 取子串:
substr(int 起始, int 长度)
- 取字符:
at(int x)
- 删除子串:
erase(int 起始, int 长度)
- 将rope从pos开始的len个字符用s替代
copy(int pos, int len, string &s/int *a)
- 将rope从pos开始的字符用s替代
replace(int pos, string &s/int *a);
3. stl
-
stl奇技淫巧不多,也很常用,不用错就行了。
-
set
- 一个元素只能出现一次
- 删除元素之后结构可能发生改变,因此不要边删边跑迭代器。迭代完之后统一删除。
- multiset可以出现多个元素
- 删除一个值,删除所有等于该值的结点
- 要只删除一个值,就删除一个等于该值的指针
-
map
- map nb!
-
bitset用法整理,转自胡小兔的博客
foo.size()
返回大小(位数)
f11oo.count()
返回1的个数
foo.any()
返回是否有1
foo.none()
返回是否没有1
foo.set()
全都变成1
foo.set(p)
将第p + 1位变成1
foo.set(p, x)
将第p + 1位变成x
foo.reset()
全都变成0
foo.reset(p)
将第p + 1位变成0
foo.flip()
全都取反
foo.flip(p)
将第p + 1位取反
foo.to_ulong()
返回它转换为unsigned long的结果,如果超出范围则报错
foo.to_ullong()
返回它转换为unsigned long long的结果,如果超出范围则报错
foo.to_string()
返回它转换为string的结果