STL++?pb_ds平板電視初步探索

什麼是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";
  }
}
相關文章
相關標籤/搜索