無旋treap學習小記

2021-08-29 04:35:03 字數 2807 閱讀 2164

高一才學這麼基本的平衡樹,退役了~

鑑於旋轉treap不能可持久化,與splay相比除了常數小以外沒有什麼不同,所以就不學了。

treap = tree + heap,即二叉搜尋樹+堆

它的中序遍歷是有序的,這是二叉搜尋樹的性質。

且對於每乙個點有乙個隨機的鍵值,對於整個樹的任意一棵子樹,鍵值滿足堆的性質。

基於隨機,樹高期望是log的。

核心操作有兩個:

split和merge

即分離和合併。

split(x,k)表示把x為根的搜尋樹的前k個分離出來。

merge(a,b)表示合併以a為根和以b為根的搜尋樹。

注意b樹的搜尋樹值一定要都在a樹的右邊才能用merge合併,不然就一定要乙個個提出來插進去。

這兩個操作只要有點智商都寫得出來,只是優不優美的問題,標程放文章的最後。

注意到無論是split還是merge每次影響到的點都只有log個,且因為每次都是自上而下地遍歷整棵樹,所以這個是可以線段樹一樣可持久化的,寫法會差不多。

注意treap中用到了隨機,因為c++自帶的rand()函式特別慢,所以一般手寫。

真正實現的時候並不是給每個點乙個鍵值,而是在merge的時候根據兩棵子樹的大小來加權再隨機來決定誰在上面。

平衡樹例題:

bzoj 3224: tyvj 1728 普通平衡樹

可持久化treap例題:

jzoj 3658. 【noi2014模擬】『『文字編輯器

t1:

#include

#define x0 t[x][0]

#define x1 t[x][1]

#define ul unsigned long long

#define fo(i, x, y) for(int i = x; i <= y; i ++)

using namespace std;

const

int n =

1e5+5;

const

int inf =

2e9+1;

int n, op, x;

int rt, t[n][2

], siz[n]

, c[2]

, z[n]

, td;

ul zz =

998244353

; ul randx()

void

upd(

int x)

void

split

(int x,

int k)

intmerge

(int a,

int b)

else

}intgr(

int x,

int k)

void

ins(

int k)

void

del(

int k)

intfi

(int x,

int k)

intpre

(int x,

int k)

return

pre(x0, k);}

intnxt

(int x,

int k)

return

nxt(x1, k);}

intmain()

}

t2:

#include

#define x0 t[x][0]

#define x1 t[x][1]

#define ll long long

#define ul unsigned long long

#define fo(i, x, y) for(int i = x; i <= y; i ++)

using

namespace std;

const

int n =

2e7;

int t[n][2

], siz[n]

, rev[n]

, c[2]

, rt, tot, q, x, l, r, nw;

char v[n]

;ul zz =

998244353

;ul randx()

intxin

(int

&x)void

fan(

int x)

void

down

(int x)

void

upd(

int x)

void

split

(int x,

int k)

intmerge

(int a,

int b)

else

}void

ins(

int x,

char p)

void

del(

int l,

int r)

void

cpy(

int l,

int r,

int x)

void

reverse

(int l,

int r)

void

query

(int x)

intmain()

if(ch[0]

=='d')if

(ch[0]

=='c')if

(ch[0]

=='r')if

(ch[0]

=='q')}

}

總結 無旋treap

顧名思義就是沒有旋轉操作的treap.還是很好打的.畢竟旋轉操作旋轉上天.兩個核心操作 split和merge split是將一棵樹分成兩棵樹的操作.注意這裡的要求是對於確定的樹,將其前k個點分成新樹,剩下的點變成另一顆新樹,因此可能出現多個切割的地方.對於乙個節點來說,我們必然只會處理它的一顆子樹...

無旋treap的初步學習

是一種詭異的平衡樹 最主要的操作 就是split 拆分成兩棵子樹 和merge 合併為一棵子樹 這個。就不講了吧。因題而異。所以我寫出來是為了什麼?分為兩種 一種是以前k個和剩下的來拆分,適用於區間操作時 r1為前k個的子樹的根,r2為剩下的子樹的根 void split treap int x,i...

fhq treap(無旋treap) 學習筆記

首先最好要會寫treap 也先了解一下笛卡爾樹是什麼。fhq treap和treap同樣有乙個隨機分配的rnd值,用於平衡,但fhq treap不需要旋轉操作來維持平衡,因為有兩個神奇的操作merge和split 在兩種操作之前,要明確的一點是fhq treap依靠rnd值來維護平衡,把每個點按照小...