平衡樹之Treap

2021-07-26 08:00:06 字數 4144 閱讀 9012

–乙個集合支援快速插入、刪除乙個數字。

–支援快速查詢乙個數字在所有已插入數字中的排名。

–支援刪除大小在某乙個區間內的數字。

動態維護乙個數列。可以在數列的任何位置插入刪除,求區間和,

min,

max,進行區間翻轉

這就需要用到二叉查詢樹(

binary search

tree

)。•性質:

–這是一棵二叉樹。

–對於任意乙個節點,左子樹的所有節點權值小於該節點權值,右子樹所有節點權值大於該節點權值。

常見二叉查詢樹-------treap

•treap

在基本的二叉搜尋樹基礎上增加了乙個

『隨機附加域』

,整棵樹不僅要滿足二叉搜尋樹

左兒子小右兒子大

的性質,

同時也要滿足按照

『隨機附加域』

成乙個堆

。正因為

附加域的隨機性,使得

treap

可以保持乙個較為隨機的結構

,其平均樹高為

o(logn)級別

,這也是它能夠實現基本操作時間複雜度

o(logn

)的原因。 

treap的儲存

•通常來說我們用乙個

結構體來儲存乙個

treap

節點:

•struct 

treap_node •

因為平衡樹是乙個動態的結構,所以節點需要動態的開(

記憶體池)

int  

tot=

0;//

記錄當前記憶體池中哪些節點已經使用

獲取乙個新節點:

inline

treap_node

*get_new

(int

value

)•上面的**裡面出現了乙個

null

,注意和空指標

null

區分。•因為訪問空指標會引起

re,為了避免麻煩,我們自己造乙個假的空指標

,這個指標

null

指向乙個沒有用的結構體。

•null

的size=0

,key=inf

,這樣根據堆的性質能保證它待在最底下而不會跑上來

treap的旋轉

wh=0;(左孩子)

treap_node *child = now->ch[wh];

now->ch[wh] = child->ch[wh ^ 1];

child->ch[wh ^ 1] = now;

now->update();

child->update();

•我們的

treap

節點會維護一些和子樹有關的資訊,比如

size

(子樹裡面節點的個數)。當子樹發生變化的時候,就需要更新這些資訊:

void 

treap_node

::update()

•在實際應用中,

update

函式還有可能維護一些別的資訊,比如子樹裡面

節點權值的最大者,節點權值和

等等。

插入

新節點的步驟:

–先獲取乙個新節點

–找到該新節點應該插入的位置。

–根據隨機附加域進行調整,直到滿足堆的性質(旋轉)。

void insert(treap_node *&now, int value)

if (now->value==value) return;

int wh=value < now->value ? 0 : 1;

insert(now->ch[wh], value);

now->update();

int minwh=  

now->ch[0]->key < now->ch[1]->key ? 0:1;

if (now->ch[minwh]->key  <  now->key)

rotate(now,minwh);//旋轉}

treap

的刪除

•如果乙個節點是葉子節點,我們能夠很方便的刪除。

•所以我們的思路是,把要刪除的點挪到葉子節點的位置。

•一路旋轉,注意還要維護堆的性質。

void del(treap_node *&now, int value)

else now=null;

}else}

treap的查詢

•和insert,del

函式中的查詢方式一樣。值小向左走,值大向右走。

treap計算r

ank

•計算乙個數字當前是第幾小(大)的

•首先不停的查詢這個數字。如果當前要向左走,答案不變;如果當前要向右走,答案要

+左子樹的大小+1。

int rank(treap_node *now,int value)

treap找第k

•這個過程和計算

rank

正好相反。

•看一下

k和當前左子樹大小的關係:

–如果k<=

ch[0]->size

,往左走。

–如果ch[0]->size+1==k

,bingo

–如果ch[0]->size+1,往右子樹走,

k-=ch

[0]->size+1

int zd(treap_node *now,int k)

•treap

相對於其它平衡樹的優點是實現方便,且常數比較優良。

•缺點是功能不夠強大。所以我們競賽中通常採用

splay而非

treap。

#include #include #include #include #include using namespace std;

const int inf = 1e9;

const int max_q = 2e5 + 10;

struct treap_node

} pool[max_q], *root, *null;

int top = 0;

inline treap_node *get_new(int value)

inline void rotate(treap_node *&now, int wh)

void insert(treap_node *&now, int value)

if (now->value == value)

return;

int wh = value < now->value ? 0 : 1;

insert(now->ch[wh], value);

now->update();

int minwh =

now->ch[0]->key < now->ch[1]->key ? 0 : 1;

if (now->ch[minwh]->key < now->key)

rotate(now, minwh);

}void del(treap_node *&now, int value)

else

now = null;

} else

}inline int kth(treap_node *now, int k)

int cou(treap_node *now, int value)

inline int get_num()

int main()

}}

平衡樹之非旋Treap

線段樹不支援插入or刪除乙個數於是平衡樹產生了 常見平衡樹 treap 比sbt慢,好寫吧 sbt 快,比較好寫,有些功能不支援 splay 特別慢,複雜度當做根號n來用,功能強大,不好寫 rbt 紅黑樹,特別快 替罪羊樹,朝鮮樹 晚上要講的不旋轉平衡樹 節點的左兒子中的每乙個一定比他小,右兒子中的...

Treap 普通平衡樹

最近學習了treap,找了道題目做做 全抄hz.因為普通的二叉樹,會退化成鏈 所以你把讀入打亂順序再構造二叉樹,就明顯卡不掉 平平均深度logn treap就是這樣的 在插入乙個數時,我們搞乙個rnd,賦值隨機 然後如果當前的這個節點rnd小於其父節點,那麼就把他轉到父節點的位置 這樣好比是給這個節...

平衡樹模板 Treap

演算法標籤 treap 種下第一棵平衡樹 這是一道模板題。如果覺得這個題水的可以做一下4544壓行,是千古神犇花爸爸出的神犇題。您需要寫一種資料結構 可參考題目標題,但是這句話其實並沒有什麼用233 來維護一些數,其中需要提供以下操作 1.插入x數 2.刪除x數 若有多個相同的數,因只刪除乙個 3....