替罪羊樹學習筆記

2022-05-01 19:12:07 字數 1530 閱讀 9667

部落格咕咕咕了好久……最近會逐步繼續恢復更新部落格的。

最近又在學習二叉搜尋樹。實測發現替罪羊樹快的飛起(時間約splay的1/2)~寫起來還比較簡單,決定來一波。

(那為什麼還要用splay呢?因為splay是序列之王!還能維護lct!(你要用非旋treap(fhq-treap)我也沒意見))

替罪羊樹的主要思想就是當出現重量失衡的時候,把罪魁禍首的那個子樹拎出來,重新按最完美的方式(也就是近似完全二叉樹)構造一遍再接回去

如何定義某個子樹不平衡:當這個子樹的左右子樹其中之一的「重量」(節點個數)超過了整個子樹的α*100%時,我們認為這個子樹不平衡。

舉例:α=0.75時,如果乙個子樹左子樹有4個節點,右子樹有1個,這個子樹大小就是4+1+1=6,左子樹佔比超過了α*100%(即75%),這個子樹不平衡,需要重構。

顯然,α取值介於0.5至1.0之間,越小樹越平衡但重構次數越多,越大重構次數越少但樹越不平衡。太大太小都會出事。一般而言,α取0.75。如果題目查詢次數遠大於插入次數,可略微降低α取值(比如α=0.70);若遠小於,則略公升高(如α=0.80)。

下面以洛谷3369【模板】普通平衡樹為例:

//這個板子有改進之處:比如刪除節點可以打上刪除懶標記,單個節點可以記錄同一數字數量避免多餘節點。

#include#include#include#define inf (1<<30)

#define maxn (2100000)

#define db double

#define il inline

#define rg register

using namespace std;

const db al=0.75;//α

struct node t[maxn];

int n,cnt,root;

il bool balance(rg int id) //判斷子樹是否平衡

int cur[maxn],sum;

il void recycle(rg int id) //壓扁,把需要重構的子樹拎出來先拍扁成序列

il int build(rg int l,rg int r) //遞迴建樹,使結構最優

il void rebuild(rg int id) //重構子樹,再「接回去」

il void insert(rg int x)//插入乙個數字x

}rg int flag=0;

for(rg int i=cur; i; i=t[i].fa) if(!balance(i)) flag=i;//注意:重建時取深度最淺的,以避免小子樹重構完大子樹還重構,浪費時間

if(flag) rebuild(flag); //插入往往會導致不平衡,這時需要重建不平衡的子樹即可

}il int get_num(rg int x) //查詢 x 在樹中的節點編號(在陣列中儲存位置下標)

return now;

}int main()

return 0;

}

替罪羊樹學習筆記

教練講旋轉的時候摸魚去了,然後就不會旋轉操作了t t,那怎麼辦呢,要做題的啊,誒,替罪羊樹好像是不用旋轉的誒qwq,就它了。替罪羊樹這樣直接講不直觀,還是看題來講吧。上題 洛谷 p3369 模板 普通平衡樹 概念 思想 替罪羊樹屬於平衡樹的一種,但是他維護平衡的方式不是複雜的旋轉,而是直接把這棵子樹...

替罪羊樹學習筆記

替罪羊樹是一種平衡樹。然而它既不能可持久化,又不能維護區間。所以把它發明出來幹嘛?然而它可以維護子樹內資訊。這個是一眾平衡樹都不能做到的功能。它維護平衡的方式和普通的平衡樹瘋狂旋轉不太一樣。它是如果這個子樹不平衡就把這個子樹拍平了重構。具體地,如果左子樹的節點數和右子樹的節點數比值超過某個值或小於某...

總結 替罪羊樹學習筆記

突然不會寫學習筆記了.反正是給自己看的 那就想到哪寫到哪吧 不基於旋轉而基於暴力重構的平衡樹 採用懶惰刪除法 每次刪除只打標記,在重構時統一刪除 如果某個點的子樹過於不平衡或刪除了過多的元素 那就需要進行重構 重構時暴力dfs整棵子樹,碰見打了刪除標記的節點就扔進記憶體池,否則按照中序遍歷存下來,然...