什麼是pb_ds?
除了衆所周知的STL庫,c++還自帶了ext庫(應該能夠這麼叫吧),其中有用pb_ds命名的名稱空間(俗稱平板電視)。這個名稱空間下有四個數據類型結構。這些都是不爲人知的。通過測試目前全部的OJ都支持pb_ds庫,OI聽說也支持。網上資料顯示只要是稍微高級一點的linux判卷機都是支持的。這個庫的網上資料甚少,百度wiki也沒有找到相關的詞條,我靠東拼西湊湊出來這麼一篇不成形的博客,之後也會繼續研究更新
pb_ds包含的數據結構
導言
要想運用pb_ds庫有兩種方法
①直接使用
#include<bits/extc++.h>
using namespace __gnu_pbds;//兩個_在gnu前面
可是惋惜的是這個頭文件大部分的oj仍是不支持的,而且本地的dev也不支持,因此仍是不要這麼寫的好
②按照需求寫頭文件
#include <bits/stdc++.h>
#include <ext/pb_ds/assco_container.hpp>//這個必須在各個pb_ds的數據結構以前寫,不知道爲啥
using namespace __gnu_pbds;
①哈希
哈希你們都知道,就是一種映射。可是咱們STL中已經有map了,這個還有什麼用呢?實際上根據網上資料顯示這個hash_table比map要快map是nlogn這個是n。
頭文件
#include <ext/pb_ds/hash_policy.hpp>
定義方法有兩種
cc_hash_table<int,bool> h;
gp_hash_table<int,bool> h;
根據網上的大佬評測後者速度更快一些。
具體用法跟map類似不在贅述,下面擺一個示例用pb_ds庫中的哈希作的a+b且在QLUOJ上經過
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
gp_hash_table<long long,long long> mp;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
long long a,b;
cin>>a>>b;
mp[0]=a;
mp[1]=b;
cout<<mp[0]+mp[1];
}
感受能夠是map的上位替換
②堆(優先隊列)
基本運用與STL的優先隊列沒有什麼其餘的區別,多了堆的合併操做和分離操做
頭文件
#include <ext/pb_ds/priority_queue_policy,hpp>//真的長
定義方法
priority_queue<int,greater<int>,TAG> Q;
第一個參數是數據類型
第二個是排序方式
第三個是堆的類型
其中堆的類型有下面幾種
pairing_heap_tag
thin_heap_tag
binomial_heap_tag
rc_binomial_heap_tag
binary_heap_tag
其中pairing_heap_tag最快
而且這個東西是帶默認參數的,只須要定義一個int也能夠
①join函數
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
//using namespace __gnu_pbds;
__gnu_pbds::priority_queue<int> a,b;//注意這個地方爲了不與std的stl發生衝突,因此帶上名稱空間
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
while(n--)
{
int t1;
cin>>t1;
a.push(t1);
}
while(m--)
{
int t1;
cin>>t1;
b.push(t1);
}
a.join(b);
while(a.size())
{
cout<<a.top()<<" ";
a.pop();
}
}
這樣會把兩個優先隊列合併成一個,b優先隊列清空
結果

②split函數用法
此處省略,材料過少沒法知道split函數的第一個參數的具體意思
③trie字典樹
我以爲徹底沒有什麼卵用的東西,只能完成基本的模板操做,並且不知道爲啥我試了試還超時,是否是我姿式不對,網上也說沒啥用
頭文件
#include<ext/pb_ds/trie_policy.hpp>
具體用法(這裏複製了洛穀日報第三十九期)
typedef trie<string,null_type,trie_string_access_traits<>,pat_trie_tag,trie_prefix_search_node_update> tr;
//第一個參數必須爲字符串類型,tag也有別的tag,但pat最快,與tree相同,node_update支持自定義
tr.insert(s); //插入s
tr.erase(s); //刪除s
tr.join(b); //將b併入tr
pair//pair的使用以下:
pair<tr::iterator,tr::iterator> range=base.prefix_range(x);
for(tr::iterator it=range.first;it!=range.second;it++)
cout<<*it<<' '<<endl;
//pair中第一個是起始迭代器,第二個是終止迭代器,遍歷過去就能夠找到全部字符串了。
遍歷一個前綴所包含的單詞數(hdu1251 TLE)多是個人操做問題。。。
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/trie_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef trie<string,null_type,trie_string_access_traits<>,pat_trie_tag,trie_prefix_search_node_update> tr;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
tr base;
string a;
while(getline(cin,a))
{
if(a.size()==0)
break;
else
base.insert(a);
}
string b;
while(getline(cin,b))
{
int sum=0;
auto range=base.prefix_range(b);
for(auto it=range.first;it!=range.second;it++)
sum++;
cout<<sum<<"\n";
}
}
反正trie建議手搓
④平衡樹
這個真心的感受是這裏面最牛逼的,因此我放倒了壓軸的位置。惟一須要注意的是這個平衡樹是set的形狀,也就是說他是會自動去重的。。。固然也能夠不自動去重,可是目前我尚未研究出來
頭文件
#include <ext/pb_ds/tree_policy.hpp>
具體用法
能夠理解爲是set++
tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;
第一個參數是數據類型
第二個參數是沒有映射直接照抄便可
第三個排序方式
第四個是平衡樹的類型,這裏網上一致認爲紅黑樹最快,好像比手搓的還快?
第五個是自定義節點更新方式(這個能夠自定義,可是我目前不會)
//這一部分更改於洛穀日報第39期
tr.insert(x); //插入;
tr.erase(x); //刪除;
tr.order_of_key(x); //求排名
tr.find_by_order(x-1); //找k小值,返回迭代器
tr.join(b); //將b併入tr,前提是兩棵樹類型同樣且沒有重複元素
tr.split(v,b); //分裂,key小於等於v的元素屬於tr,其他的屬於b
tr.lower_bound(x); //返回第一個大於等於x的元素的迭代器
tr.upper_bound(x); //返回第一個大於x的元素的迭代器
//以上全部操做的時間複雜度均爲O(logn)
完整代碼
1.插入x數
2.刪除x數(如有多個相同的數,因只刪除一個)
3.查詢x數的排名(排名定義爲比當前數小的數的個數+1。如有多個相同的數,因輸出最小的排名)
4.查詢排名爲x的數
5.求x的前驅(前驅定義爲小於x,且最大的數)
6.求x的後繼(後繼定義爲大於x,且最小的數)
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> a;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
while(n--)
{
int t1,t2;
cin>>t1>>t2;
if(t1==1)
a.insert(t2);
else if(t1==2)
a.erase(t2);
else if(t1==3)
cout<<a.order_of_key(t2)<<"\n";
else if(t1==4)
cout<<*a.find_by_order(t2-1)<<"\n";
else if(t1==5)
cout<<*--a.lower_bound(t2)<<"\n";
else if(t1==6)
cout<<*a.upper_bound(t2)<<"\n";
}
}