Treap 旋轉 bzoj3224普通平衡樹

2021-08-27 05:57:55 字數 3213 閱讀 8281

treap = tree + heap,tree是bst,即同時維護二叉查詢樹和堆的性質

treap的定義:

int ch[maxn][2], val[maxn], siz[maxn], num[maxn], pri[maxn];//此處優先順序用了小根堆

int tot, rt;

#define ls ch[now][0]

#define rs ch[now][1]

ch陣列存的是左右孩子節點的下標

val是bst的值,siz是子樹大小,

num指值為val的數有多少個

pri是堆的值(此處選擇了小根堆)

tot是treap的結點總數(val相同的很多個數只佔乙個結點)

rt是當前的樹根

巨集是拿來偷懶滴

1、一棵bst,無論如何左旋右旋,結點間的關係一定不會變。

2、bst在資料隨機的情況下所有操作的期望都是o(logn)

treap就是利用以上兩點,把插入的資料通過旋轉,變得好像是隨機插入的一樣。

treap的每次插入,先像普通的bst一樣找到插入的位置,然後給pri賦隨機值,再以旋轉的方式用pri在不改變bst的性質的前提下維護heap。

旋**

旋轉後siz會變,要更新

inline void pushup(int now)

void rotate(int &x,int

dir)//把now旋轉到它的兒子的位置,dir為0代表右旋,1左旋

插入乙個值為v的數:

遞迴寫起來比較舒服~

4種情況:

1、找到了乙個空位

新建乙個點,over

2、當前節點的val == v

當前結點的num+1,over

3、當前節點的val > v

遞迴往左子樹插入

檢查左孩子的pri是否小於當前的pri,小於則右旋(左子樹完成插入後可能不滿足堆的性質)

4、跟3反過來

一路上的siz都要++(下面多了乙個數)

void insert(int v,int &now)

++siz[now];

if(val[now] == v)//這個數已經存在,num+1即可

else

if(v < val[now])

else

}

刪除乙個值為v的數:

3種情況 吧

1、如果找到val == v的結點,且該結點的num > 1,num-1就行了

2、找到val == v的結點,且該結點的num == 1

(1)如果沒有左右子樹,直接賦個0刪了就行

(2)如果左右子樹中有乙個為空,賦值為不為空的那個(就是直接拿孩子把它覆蓋掉)

(3)如果左右子樹都有,把孩子中pri小的那個轉上來(維護堆的性質不變),然後再遞迴刪當前結點(為什麼不是刪孩子結點?因為旋轉完,當前節點已經轉到孩子那裡去了啊)

3、val != v

遞迴刪左或右即可

一路上的siz都要-1

3的(3)siz不用-1,因為轉上去的孩子siz都是沒變的,轉下去的那個點被刪了,不用管它的siz

void dele(int v,int &now)

else

else

if(!ls || !rs)

else}}

else

}

查值為v的數的排名

比較簡單 ,直接看注釋吧

int rk(int v,int now)

查排名為k的數:

跟上面差不多

int kth(int k,int now)

求前驅、後繼

int pre(int v,int now)

int suc(int v,int now)

bzoj3224普通平衡樹:

#include

#include

#include

#include

using

namespace

std;

const

int maxn = 1e5 + 5;

const

int inf = 1e9 + 9;

int ch[maxn][2], val[maxn], siz[maxn], num[maxn], pri[maxn];//優先順序用小根堆

int tot, rt;

#define ls ch[now][0]

#define rs ch[now][1]

queue

que;

inline

void newnode(int v,int &x)

else

x = ++tot;

ch[x][0] = ch[x][1] = 0;

num[x] = 1;

val[x] = v;

siz[x] = 1;

pri[x] = rand();

}inline

void reuse(int x)

inline

void pushup(int now)

void rotate(int &x,int dir)//把now旋轉到它的兒子的位置,dir為0代表左兒子

void insert(int v,int &now)

++siz[now];

if(val[now] == v)//這個數已經存在,num+1即可

else

if(v < val[now])

else

}void dele(int v,int &now)

else

else

if(!ls || !rs)

else}}

else

}int rk(int v,int now)

int kth(int k,int now)

int pre(int v,int now)

int suc(int v,int now)

int n,op,x;

int main()

}return

0; }

Treap的實現方法 BZOJ 3224

傳說,有一種排序二叉樹叫做treap。而 treap tree heap 所以,treap既具有樹,也具有堆的性質。它的基本操作和普通的樹相近,但也有一些差異。以上全部為亂講系列 如果要看詳細介紹,這裡給出lmy大神關於平衡樹的研究講解 詳細介紹之後會補充的 首先,它的儲存方式和其他的二叉樹類似,都...

bzoj3224普通平衡樹

您需要寫一種資料結構 可參考題目標題 來維護一些數,其中需要提供以下操作 1.插入x數 2.刪除x數 若有多個相同的數,因只刪除乙個 3.查詢x數的排名 若有多個相同的數,因輸出最小的排名 4.查詢排名為x的數 5.求x的前驅 前驅定義為小於x,且最大的數 6.求x的後繼 後繼定義為大於x,且最小的...

BZOJ3224 普通平衡樹

題目傳送門 您需要寫一種資料結構 可參考題目標題 來維護一些數,其中需要提供以下操作 1.插入x數 2.刪除x數 若有多個相同的數,因只刪除乙個 3.查詢x數的排名 若有多個相同的數,因輸出最小的排名 4.查詢排名為x的數 5.求x的前驅 前驅定義為小於x,且最大的數 6.求x的後繼 後繼定義為大於...