平衡樹 替罪羊樹

2021-08-20 11:05:29 字數 2970 閱讀 3283

–yangkai

身為平衡樹卻不做任何形式的旋轉,替罪羊樹可以稱得上是最暴力的平衡樹了。

替罪羊樹(sgt)保留有二叉搜尋樹的基本性質,即對於任意乙個節點t,左兒子的所有節點比它小,右兒子的所有節點比它大。但是既然不基於翻轉,它怎樣維護平衡樹的優秀複雜度呢?

sdt基於乙個叫做「重構」的操作,聽起來很是優美暴力,那麼我們要如何重構?

首先,如果要時刻維持平衡樹的平衡,即ab

s(si

z[l]

−siz

[r])

<=

1 abs

(siz

[l]−

siz[

r]

)<=

1,顯然我們平均每兩次插入、刪除操作就需要一次重構,這樣的時間效率接近o(

n2) o(n

2)

,所以我們可以取乙個閾值[0.5,1.0],當且僅當左右子樹超過閾值的限制重構子樹。在這裡我們可以發現,當閾值限制越緊[0.5,0.75],對修改少詢問多有利;當閾值限定越鬆[0.75,1.0],對修改多查詢少有利。

根據閾值,我們就可以對子樹進行重構了。

但是問題又來了,在條根到葉子的鏈上可能有許許多多的「不平衡點」,我們要怎樣確定最優的乙個,實際上,我們只需要選擇最靠近根節點的乙個就好了,因為如果修改的層數太深,在總體上不會對樹的結構產生多麼大的影響,所以選最靠近根的乙個相對來說比較優秀。

那麼維護平衡樹性質的部分我們解決了,但是插入以及刪除呢?

首先,對於插入,直接參見動態開點**,在向下插入的時候動態開點就好了(此處應該注意**記憶體)

其次,對於刪除,我們既不能把它轉到葉子結點(treap),也不能直接裂開丟掉再合併(非旋轉treap),所以我們給它打上乙個real標記,real標記存在說明這個節點資訊為』真『,否則為『假』(已經刪除),然後在重構子樹的時候直接丟掉然後**記憶體就好了

其他操作rank,get_kth,pre,nxt之類的操作直接套用平衡樹常見套路就好了

然後寫陣列版的朋友們要注意

需要維護父親和兒子的關係

不然會莫名其妙地丟失子樹

description

您需要寫一種資料結構(可參考題目標題),來維護一些數,其中需要提供以下操作:

\1. 插入x數

\2. 刪除x數(若有多個相同的數,因只刪除乙個)

\3. 查詢x數的排名(若有多個相同的數,因輸出最小的排名)

\4. 查詢排名為x的數

\5. 求x的前驅(前驅定義為小於x,且最大的數)

\6. 求x的後繼(後繼定義為大於x,且最小的數)

input

第一行為n,表示操作的個數,下面n行每行有兩個數opt和x,opt表示操作的序號(1<=opt<=6)

output

對於操作3,4,5,6每行輸出乙個數,表示對應答案

sample input

10 1 106465

4 1

1 317721

1 460929

1 644985

1 84185

1 89851

6 81968

1 492737

5 493598

sample output

106465

84185

492737

hint

1.n的資料範圍:n<=100000

2.每個數的資料範圍:[-2e9,2e9]

上板子

//yangkai 

#include

using

namespace

std;

inline

int read()

struct sgt

void del_place(int t)

void clean_st()

//sgt

int root;

int ls[n],rs[n],fa[n];

int val[n],siz[n],all[n];

bool real[n];

void pushup(int t)

bool check(int t)

int newnode(int vl=0,int f=0)

//收集需要重構的下標

void collect(int t,vector

&v)

//重構劃分

int divide(int l,int r,vector

v)//重新建樹

void rebuild(int &t)

//查詢vl的排名

int rank(int vl)

}return ans;

}//查詢排名為k的數

int get_kth(int k)

} //插入vl值

int insert(int &t,int f,int vl)

int res;

if(vl<=val[t])res=insert(ls[t],t,vl);

else res=insert(rs[t],t,vl);

pushup(t);

//檢查是否需要重構

if(check(t))res=t;

return res;

}void insert(int vl)

}//刪除排名為k的數

void erase(int t,int k)

if(k<=siz[ls[t]])erase(ls[t],k);

else erase(rs[t],k-siz[ls[t]]-real[t]);

}//刪除數vl

void erase(int vl)

int nxt(int vl)

//輸出除錯

void out_put(int t)

}sgt;

int main()

}return

0;}

替罪羊樹模版 普通平衡樹

替罪羊樹,賊長,我哭了。include include include include include using namespace std const int maxn 1e5 5 const double alpha 0.75 struct nodetzy maxn intcnt,root 新...

初涉平衡樹 替罪羊樹

替罪羊樹 乙個看上去很玄學的名字 替罪羊 這個名字非常有趣 以至於一開始我並不覺得這是什麼好懂的東西 名字的 大概是由於它在刪除時候需要用被刪除節點的 左子樹最後乙個節點 右子樹第乙個節點來頂替這個節點。資料結構圈居然還有這麼腦洞的名字 好像還有乙個東西叫做朝鮮樹來著?替罪羊的精華在於,它相較於其他...

平衡樹學習筆記(2) 替罪羊樹

1.重構 2.插入 3.查詢 4.刪除 5.判斷重構 6.綜合運用 一些廢話 總結 中考加油!想學替罪羊樹很久了,剛開始接觸平衡樹的時候就久仰替罪羊樹的大名,但是無奈經驗和理解能力都有些欠缺,暫時放了下,這幾天題目難度不大,有了時間來學替罪羊樹。其實替罪羊樹之所以看起來高深,有80 的原因是因為名字...