1. 程式人生 > >題解 P3369 【【模板】普通平衡樹(Treap/SBT)】

題解 P3369 【【模板】普通平衡樹(Treap/SBT)】

為什麽 平衡樹 -m cout 指向 erase out 刪除 play

STL真是個好東西。

最近在看pb_ds庫及vector和set的用法,就想用這三種操作來實現一下普通平衡樹,結果pb_ds中的rbtree不支持重復值,而本蒟蒻也看不懂不懂各大佬用pb_ds的實現,況且應該有人已經貼上了題解。我就發一發vector和set(其實是multiset)的題解吧。(只不過蒟蒻的我我根本不會打splay)

代碼都很短,操作其實也很基礎。


vector版:

  • 你要知道:

    • lower_bound(first,last,x)在first和last中的前閉後開區間進行查找,其中如果尋找的x存在,那麽lower_bound返回一個叠代器指向其中第一個x元素。

    時間復雜度:O(logN)

    • upper_bound(first,last,x)在first和last中的前閉後開區間進行查找,返回一個叠代器指向最後一個x元素的下一個位置(就是說返回在保持順序的情況下,可插入x的最後一個位置或者說就是返回x的後繼)

      時間復雜度:O(logN)

    • vector.insert(pos,x)在pos處插入一個x

    vector.erase(pos,x)在刪除pos處的x

    時間復雜度:這個不太清楚,貌似是O(N)

然後你就能看懂下面的代碼了

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cctype>
using namespace std;
vector <int>a;
int read()
{
    int x=0;char ch;short int neg=0;ch=getchar();
    while(!isdigit(ch)){
        neg|=(ch==‘-‘);ch=getchar();
    }
    while(isdigit(ch)){
        x=x*10+ch-48;ch=getchar();
    }
    return neg?-x:x;
}
int main()
{
    int n,op;
    cin>>n;
    while(n--)
    {
        cin>>op;
        register int x=read();
        switch(op){ 
  case(1):a.insert(upper_bound(a.begin(),a.end(),x),x);break;
  case(2):a.erase(lower_bound(a.begin(),a.end(),x));break;
  case(3): cout<<lower_bound(a.begin(),a.end(),x)-a.begin()+1<<endl;break;
  case(4): cout<<a[x-1]<<endl;break;
  case(5): cout<<*--lower_bound(a.begin(),a.end(),x)<<endl;break;
  case(6): cout<<*upper_bound(a.begin(),a.end(),x)<<endl;break;
       }
    }
    return 0;
}

可以看出,我們是有序地加入元素,vector本身也是有序的

開O2跑得比香港記者還快,不開O2好像最慢的300多ms


set版:

C++ STL中的set好像是用紅黑樹實現的,但是它並不支持重復元素,所以我們只能用multiset,然而用multiset(其實set也是)搞排名之類的就好復雜了......看網上說好像是STL中的紅黑樹並沒有維護什麽size域,我也不太懂。

  • 你要知道:

    • insert和erase和上面基本一樣的

    • distance(pos1,pos2)返回一個int值為pos1與pos2之間的距離,pos1,pos2為指向同一容器的叠代器。

    時間復雜度:O(N)

    • advance(pos,k)一個void的函數,讓pos這個叠代器前進k步
    時間復雜度:O(N)
    • set.equal_range(x),它返回的一隊叠代器,因此是pair類型,定義時需註意。

    具體用法詳見這: http://blog.csdn.net/zhongguoren666/article/details/8463249

    時間復雜度:O(logN)

    由於上面操作的時間復雜度以及常數較大,用set開O2依舊會T掉幾個點,我這個代碼在O2優化時還會玄學WA了一個,我也不清楚為什麽,不知道有沒有dalao搞一個更優的set做法

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <set>
#include <cctype>
using namespace std;
multiset <int>a;
int read()
{
    int x=0;char ch;short int neg=0;ch=getchar();
    while(!isdigit(ch)){
        neg|=(ch==‘-‘);ch=getchar();
    }
    while(isdigit(ch)){
        x=x*10+ch-48;ch=getchar();
    }
    return neg?-x:x;
}
int main()
{
    int n,op;
    cin>>n;
    while(n--)
    {
        cin>>op;
        register int x=read();
      if(op==1)a.insert(upper_bound(a.begin(),a.end(),x),x);
      else if(op==2)a.erase(lower_bound(a.begin(),a.end(),x));
      else if(op==3)cout<<distance(a.begin(),a.upper_bound(x))<<endl;
      else if(op==4)
              {multiset<int>::iterator it =a.begin();
               //int k=distance(a.begin(),a+x);
               advance(it,x-1); cout<<‘ ‘<<*it<<endl;}
      else if(op==5) cout<<*--lower_bound(a.begin(),a.end(),x)<<endl;
      else { pair<multiset<int>::const_iterator,multiset<int>::const_iterator> it;
               it=a.equal_range(x);cout<<*it.second<<endl;}//cout<<*upper_bound(a.begin(),a.end(),x)<<endl;   
    }
    return 0;
}

當然,STL不會支持更多變式操作況且現在裸題也越來越少,但它用來優化某些東西或是對拍還是非常有用的。

本蒟蒻也要開始學splay了

題解 P3369 【【模板】普通平衡樹(Treap/SBT)】