登峰造極之樹 左偏樹

2021-08-07 10:47:04 字數 1462 閱讀 3975

左偏樹其實就是個堆,而且是個可並堆,可並堆是指可以在o(logn)的時間內完成兩個堆的合併的堆結構。顯然,二叉堆雖然實現容易,並且好理解,但是合併需要o(n)的時間。

左偏樹不是乙個完全二叉樹,更不是乙個平衡樹,顧名思義,它的左兒子的比重應該大於右兒子。

那麼在乙個樹中我們如何確定左兒子與右兒子的比重大小關係呢?

我們可以乙個定義:距離。

我們定義乙個左偏樹的距離是其根節點到右兒子的乙個葉子節點的路徑長度的最大值。

令其為dist[root],則易知,dist[root]=dist[rightson]+1

而左偏樹的距離是小於其根節點到左兒子的乙個葉子節點的路徑長度的最大值的。

如果乙個樹符合這樣的條件,並且滿足大根堆或小根堆的堆特性,那我們就稱其是乙個左偏樹。

由於左偏樹的合併是可以在o(logn)的時間內解決的,所以我們考慮如何運用合併完成其他的操作。

1.插入。乙個單獨的節點一定是乙個左偏樹,所以我們可以把插入當做乙個大的左偏樹與乙個單獨節點的左偏樹之間的合併。

2.**。直接把根刪掉就好了。

3.輸出根節點。如果給的是乙個點所在的堆的根,我們可以考慮用並差集。在並差集時,壓縮路徑一定要注意注意注意!!

4.刪除根節點。如果我們直接刪除根,會造成**,所以我們刪掉根後只需合併左右子樹就行了。

5.刪除某個特定的點。先找到,然後把這個特定的點的子樹取出來,把點刪掉,再把這個特定點的左右子樹合併,然後和整個的左偏樹合併。

6.合併。重中之重。

我們考慮兩個小根堆特性的左偏樹的合併。

因為左偏的特性,我們可以確定其右兒子的高度是不會超過logn的,所以我們先比較兩個左偏樹的根的權值,設兩個根分別為u,v,權值為a[u],a[v],那麼如果a[u]>a[v],我們把u,v交換使得a[u]

也就是說,我們把u的右子樹取出來,先將這個右子樹與v合併,而後整個掛到u的右邊去不就行了?遞迴搞一搞,因為右子樹的高度不會超過logn,而v的高度也不會超過logn,所以合併就是2logn=logn   o( ̄ε ̄*) 

合併**完成!

給道模板題吧:洛谷p3377,並差集的路徑壓縮一定要注意,再次強調!

#include#includeusing namespace std;

const int n=101000;

struct leftisth[n];

int n,m;

int read()

while ('0'<=ch && ch<='9')

return x*f;

}int merge(int u,int v){

if (!u || !v)return u+v;

if (h[u].key>h[v].key || (h[u].key==h[v].key && u>v))swap(u,v);

int &ul=h[u].lch,&ur=h[u].rch;

ur=merge(ur,v);

if (h[ul].dist

左偏樹總結

既然新學了左偏樹,那我就來寫一些學了左偏樹之後的總結吧 首先,它支援的是兩個堆的合併過程。那麼最容易想到的是把乙個堆的元素全部彈出,乙個乙個加入另乙個堆中,就合併了。顯然這樣合併的複雜度是o n 的,再加上程式的其他部分,很慢。我們就考慮讓複雜度減小到o logn 很恐怖,沒錯,這就是左偏樹存在的意...

左偏樹 模板

神經病也可以寫成右偏樹 具體左偏指左節點的距離 geq 右節點的距離 距離指離最近擁有空節點的節點的距離 乙個節點的值一定 或 leq 或 geq 或 其子節點的值 由於左偏性質,每次可以合併至右邊,維護左偏性質後就可以保證複雜度 被踩爆的板子 或者是我?include define ls lson...

猴王 左偏樹

題目描述 很久很久以前,在乙個廣闊的森林裡,住著n只好鬥的猴子。起初,它們各幹各的,互相之間也不了解。但是這並不能避免猴子們之間的爭吵,當然,這只存在於兩個陌生猴子之間。當兩隻猴子爭論時,它們都會請自己最強壯的朋友來代表自己進行決鬥。顯然,決鬥之後,這兩隻猴子以及它們的朋友就互相了解了,這些猴子之間...