–乙個集合支援快速插入、刪除乙個數字。
–支援快速查詢乙個數字在所有已插入數字中的排名。
–支援刪除大小在某乙個區間內的數字。
動態維護乙個數列。可以在數列的任何位置插入刪除,求區間和,
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....