pb_ds 是GNU-C++自带的一个C++的扩展库,其中实现了很多数据结构,比STL里面的功能更强大
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp> // 用tree
#include<ext/pb_ds/hash_policy.hpp> // 用hash
#include<ext/pb_ds/trie_policy.hpp> // 用trie
#include<ext/pb_ds/priority_queue.hpp>// 用priority_queue
using namespace __gnu_pbds;
---
#include<bits/extc++.h>
using namespace __gnu_pbds;
//bits/extc++.h与bits/stdc++.h类似,bits/extc++.h是所有拓展库,bits/stdc++.h是所有标准库
哈希表
其中cc开头为拉链法,gp开头为探测法,个人实测探测法稍微快一些。
啥?操作?其实就和map差不多,支持[ ]和find。
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;cc_hash_table<string,int>mp1;//拉链法
gp_hash_table<string,int>mp2;//查探法(快一些)
说明:
在不允许使用C++11的时候,pb_ds库中的两种hash函数比map的效率大大提高 ,可以代替map作为一个哈希工具,使用方法和map完全一样,一般来说查探法的效率更高
可并堆
需要的头文件:
用法和普通的优先队列一样
#include<ext/pb_ds/priority_queue.hpp>
using namespace __gnu_pbds;
__gnu_pbds::priority_queue<int>q;//因为放置和std重复,故需要带上命名空间
__gnu_pbds::priority_queue<int,greater<int>,pairing_heap_tag> q;//最快
__gnu_pbds::priority_queue<int,greater<int>,binary_heap_tag> q;
__gnu_pbds::priority_queue<int,greater<int>,binomial_heap_tag> q;
__gnu_pbds::priority_queue<int,greater<int>,rc_binomial_heap_tag> q;
__gnu_pbds::priority_queue<int,greater<int>,thin_heap_tag> q;
__gnu_pbds::priority_queue<int,greater<int> > q;
pb_ds
库的堆提供了五种tag,分别是binary_heap_tag
,binomal_heap_tag
,pairing_heap_tag
,thin_heap_tag
,rc_binomal_heap_tag
。 因为重名的原因一定要加上 __gnu_pbds::
常用操作:
push() //会返回一个迭代器
top() //同 STL
size() //同 STL
empty() //同 STL
clear() //同 STL
pop() //同 STL
join(priority_queue &other) //合并两个堆,other会被清空
split(Pred prd,priority_queue &other) //分离出两个堆
modify(point_iterator it,const key) //修改一个节点的值
平衡树
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>using namespace __gnu_pbds;
template<typename T>
using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;// rb_tree_tag 和 splay_tree_tag 选择树的类型(红黑树和伸展树)
T // 自定义数据类型
null_type//无映射(老版本g++为null_mapped_type)
less<T>//Node的排序方式从小到大排序
tree_order_statistics_node_update//参数表示如何更新保存节点信息 tree_order_statistics_node_update会额外获得order_of_key()和find_by_order()两个功能。ordered_set<Node> Tree; // Node 自定义struct 注意重载less
Tree.insert(Node); // 插入
Tree.erase(Node); // 删除
Tree.order_of_key(Node); // 求Node的排名:当前数小的数的个数 +1
Tree.find_by_order(k); // 返回排名为k+1的iterator 即有k个Node比*it小
Tree.join(b); // 将b并入Tree,前提是两棵树类型一致并且二没有重复元素
Tree.split(v, b); // 分裂,key小于等于v的元素属于Tree,其余属于b
Tree.lower_bound(Node); // 返回第一个大于等于x的元素的迭代器
Tree.upper_bound(Node); // 返回第一个大于x的元素的迭代器//以上的所有操作的时间复杂度均为O(logn)
//注意,插入的元素会去重,如set
ordered_set<T>::point_iterator it=Tree.begin(); // 迭代器
//显然迭代器可以++,--运算
P3369 【模板】普通平衡树
因为tree里不能有相同的数,但是实际会插入相同的数,所以把这些数左移20位在加上一个常数操作(n<220n<2^{20}n<220,如果a<ba<ba<b,那么一定有{(a<<20)+n}<{b<<20}\{(a<<20) +n\}<\{b<<20\}{(a<<20)+n}<{b<<20},这样就保证了在不影响相对大小关系的情况下,消除了相同的数。
别的操作看代码就可以理解了,非常巧妙的搞定了相同数的情况。
rb_tree_tag
#include<bits/stdc++.h>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
using ll=long long;template <class T=int> T rd()
{T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg;
}
template<typename T>
using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;const int N=100010;
int n,m;
ll k,ans;
ordered_set<ll> T;
int main()
{n=rd();for(int i=1;i<=n;i++){int op=rd();k=rd<ll>();if(op==1) T.insert((k<<20)+i);if(op==2) T.erase(T.lower_bound(k<<20));if(op==3) printf("%d\n",T.order_of_key((k<<20))+1);if(op == 4)ans=*T.find_by_order(k-1),printf("%lld\n",ans>>20);if(op == 5)ans=*--T.lower_bound(k<<20),printf("%lld\n",ans>>20);if(op == 6)ans=*T.upper_bound((k<<20)+n),printf("%lld\n",ans>>20);}return 0;
}
splay_tree_tag
Code from
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
#define Node pair<int,int>
map <int,int> s;
tree< Node ,null_type,less< Node >,splay_tree_tag,tree_order_statistics_node_update> T;
int n,op,x;
int main()
{scanf("%d",&n);for(register int i = 1; i <= n; i++)switch(scanf("%d%d",&op,&x), op){case 1 :T.insert(Node(x,s[x]++));break;case 2 :T.erase(Node(x,--s[x]));break;case 3 :printf("%d\n",(int)T.order_of_key(Node(x,0))+1);break;case 4 :printf("%d\n",T.find_by_order(x-1)->first);break;case 5 :printf("%d\n",T.find_by_order(T.order_of_key(Node(x,0))-1)->first);break;case 6 :printf("%d\n",T.find_by_order(T.order_of_key(Node(x,s[x]-1))+(T.find(Node(x,0)) == T.end() ? 0 : 1))->first);break;default:break;}return 0;
}
底层代码
参考以及进阶
比STL还STL?——平板电视
pb_ds库的一些常用方法
C++ __gnu_pbds(平板电视)超详细教程(C++内置的平衡树,字典树,hash)