平衡樹就是一種可以在log的時間複雜度內完成資料的插入,刪除,查詢第k大,查詢排名,查詢前驅後繼以及其他許多操作的資料結構。
treap是一種比較好寫,常數比較小,可以實現平衡樹基本操作的一種平衡樹。treap的平衡是基於隨機化。是將堆與二叉查詢樹結合起來所得到的資料結構。
treap在插入數時,給每個數賦了乙個新的隨機的值id。在以後的操作中,必須始終使得treap中的id構成乙個堆的形態才可以。這樣就達到了平衡的目的。
struct node tr[n];
ch[0/1]分別表示左右兒子。
val是插入的數
id是賦給這個數的乙個隨機的值
cnt表示這個數字出現的次數
siz為在treap中以這個點為根的數字的個數
void up(int cur)
就是維護一下siz
f表示將左(0)還是右(1)兒子旋轉上來。
如圖
加入我們現在要把2旋轉到6這個位置,那麼旋轉之後6肯定成為了2的右兒子,那4去**呢。我們就把4變成6的左兒子,這樣就完成了旋轉。然後在維護一下siz就行了。
就成了這樣
因為treap不存父親,所以這裡要取位址,把6換成2
void rotate(int &cur,int f)
插入乙個元素時我們只要按照與二叉查詢樹相同的方法,找到乙個合適的位置插入即可。如果這個元素以前已經插入過了。那麼只要把這個數的cnt++就行了。插入完成之後,還要維護id滿足堆的形態這個條件。所以如果插入之後的兒子的id比當前節點的id小了,那麼就將兒子旋轉上來就行了。
void insert(int &cur,int val)
tr[cur].siz++;//!!
if(tr[cur].val == val)
int d = val > tr[cur].val;
insert(tr[cur].ch[d],val);
if(tr[tr[cur].ch[d]].id < tr[cur].id) rotate(cur,d);
}
首先找到要刪除的節點,根據這個節點兒子的個數可以分為兩種情況。
情況1:這個節點有1個或者0個兒子。那麼直接將這個節點變為這個節點的兒子(沒有就是0)就行了
情況2:這個節點有2個兒子。那麼不斷的往下旋轉這個節點,知道滿足情況1。在旋轉的時候應該注意,因為要滿足堆這個條件。所以應該將兒子中id較小的那個旋轉上來。
void del(int &cur,int val)
if(!ls || !rs)
int d = tr[rs].id < tr[ls].id;
rotate(cur,d);
del(cur,val);
}else tr[cur].siz--,del(tr[cur].ch[val > tr[cur].val],val);
}
這個就真的和二叉搜尋樹一樣了。如果要找的那個數字比當前節點大。那麼就將排名加上左子樹大小,然後搜右子樹,否則搜左子樹。
int rank(int cur,int val)
和查詢排名差不多。只要不斷的記錄下要查詢當前子樹中的第幾大。如果比左子樹大小加上根節點大小還大,那麼就減去左子樹大小和根大小,並查詢右子樹,否則查詢左子樹
int kth(int cur,int now)
}
還是從根往下搜尋,如果要找的數比當前根節點要大,那麼就搜尋右子樹,並將搜到的答案與當前根取max,否則就搜尋左子樹
int pred(int cur,int val)
跟前驅同理
int nex(int cur,int val)
迷途經累劫,悟則剎那間。 ——六祖壇 學習筆記 Treap
學習treap之前先學的splay,然後發現treap真是太簡單了,greatwall1995神犇的意見要聽啊 bst的缺陷是因為人為搞單調資料才爆的,隨機資料還是logn的時間,treap的思想也基於此,給每個新增的點賦乙個隨機優先值,然後整個樹關於優先值是乙個堆。clrs上要求讀者證明插入節點後...
Treap學習筆記
開乙個坑,學一學treap專題 mark乙個習題集 帶旋轉treap模板 struct treap tr 100005 int n,size,root,ans void update int k 更新結點資訊 旋轉 void rturn int k void lturn int k void ins...
Treap 學習筆記
tre ap treap trea p,顧名思義,就是tre e he ap tree heap tree h eap,是一種常見的平衡樹。b st bstbs t性質給定一棵二叉樹,樹上的每個節點帶有乙個權值。對於樹上的任意乙個節點,滿足 滿足這兩條性質的二叉樹就是 二叉查詢樹 bst bstbs...