洛谷P3369 模板 普通平衡樹 treap

2022-05-02 20:09:12 字數 1557 閱讀 9733

**:

編寫乙個資料結構在每次$o(logn)(1 \leq n \leq 1e6)$完成以下功能:

一、插入乙個數到序列中;二、在序列中刪除某乙個數;三、找到第$k$大;四、詢問第$k$大的數;五、找到$x$的前驅,六、找到$x$的後繼。

很顯然,二叉搜尋樹就可以完成這個任務,不過最壞情況下,二叉樹會退化成鏈,就會超時,因此我們就需要平衡二叉樹,其中較為容易編寫,速度又快的是$treap$。$treap$分為有旋$treap$和無旋$treap$,前者速度快,但不支援持久化,後者速度慢,但支援持久化。

treap的節點的權值維護了二叉樹的性質,為了平衡,就需要通過另外乙個數維護堆性質使其平衡,這個數就是每乙個節點對應的隨機數。旋轉的時候按照隨機數進行旋轉,分為左旋和右旋,如圖:

(參考部落格:

左旋和右旋

顯然,右旋就是原樹根的左子樹變成樹根,然後原樹根的左子樹的右子樹變成原樹根的左子樹,左旋同理。易證旋轉後二叉樹性質不變。

插入時,先找到插入點,然後回溯時旋轉。

刪除較為複雜,刪除時,先找到刪除點,然後觀察子樹的隨機數值選擇乙個子樹作為刪除後的樹根,然後通過旋轉把需要刪除的節點移動到葉子後刪除。

查詢操作易於理解,看**即可。

ac**:

#include using namespace std;

const int maxn=100005;

const int inf=0x3f3f3f3f;

struct treap

; int cnt=0;

node tr[maxn];

void init()

int _rand()

void pushup(int p)

void right(int &k)

void left(int &k)

void insert(int &p,int x)

++tr[p].size;

if(x==tr[p].val)

++tr[p].num;

else if(xtr[p].val)

}else if(tr[p].val=rnk)

return querynum(tr[p].lc,rnk);

rnk-=tr[tr[p].lc].size;

if(rnk<=tr[p].num)

return tr[p].val;

rnk-=tr[p].num;

return querynum(tr[p].rc,rnk);

}int queryfront(int &p,int x)

int queryback(int &p,int x)

};int pos;

treap tr;

int main()

; node tr[maxn];

int cnt=0;

void init()

void pushup(int p)

int _rand()

void merge(int &rt,int a,int b)//保證a的權值小於b的權值

if(tr[a].rnk

洛谷P3369 模板 普通平衡樹

本蒟蒻最近剛剛學會平衡樹,特來寫篇部落格以加深印象。我的意思是若寫的不好望各位奆佬多多包含!插入 x 數 刪除 x 數 若有多個相同的數,因只刪除乙個 查詢 x 數的排名 排名定義為比當前數小的數的個數 1 若有多個相同的數,因輸出最小的排名 查詢排名為 x 的數 求 x 的前驅 前驅定義為小於 x...

洛谷P3369 模板 普通平衡樹

插入x數 刪除x數 若有多個相同的數,因只刪除乙個 查詢x數的排名 排名定義為比當前數小的數的個數 1。若有多個相同的數,因輸出最小的排名 查詢排名為x的數 求x的前驅 前驅定義為小於x,且最大的數 求x的後繼 後繼定義為大於x,且最小的數 輸入格式 第一行為n,表示操作的個數,下面n行每行有兩個數...

洛谷P3369 模板 普通平衡樹 Treap

插入xxx數 刪除x xx數 若有多個相同的數,因只刪除乙個 查詢x xx數的排名 排名定義為比當前數小的數的個數 1 1 1。若有多個相同的數,因輸出最小的排名 查詢排名為x xx的數 求x xx的前驅 前驅定義為小於x xx,且最大的數 求x xx的後繼 後繼定義為大於x xx,且最小的數 總算...