1. 程式人生 > >[左偏樹][學習筆記]

[左偏樹][學習筆記]

主要應用

首先要知道左偏樹是用來幹什麼的。如果給我們兩個優先序列,然後讓我把這兩個優先佇列合併成一個優先佇列。如果直接用堆,就是將一個佇列裡面的數不斷彈出然後扔到另一個佇列裡。複雜度是\(n(logn)\)n為佇列中數的個數。但是用左偏樹就可以做到\(log(n_1 + n_2)\)

PS:為了便於討論,本文所有的左偏樹均已小根樹為例。

兩個定義

外節點: 至少一個兒子為空的節點稱為外節點。

距離: 某個節點的距離定義為這個節點到他的子樹中離他最近的那個外節點的距離。這個的作用讀完全文可能就明白了。

左偏樹的性質

性質1:任何一個節點的兒子一定比這個節點的數小。

性質2:任何一個節點的左兒子的距離一定大於等於右兒子的距離

性質3:任何一個節點的距離等於他的右兒子的距離+1。(空節點的距離為-1)

性質4:一棵n個節點的左偏樹中,距離最大的節點的距離不超過\(log(n + 1) -1\)

合併

繼續考慮一開始那個合併兩個優先佇列的問題。首先我們肯定不想一個一個的加入佇列。而是最好可以通過改變一些節點的兒子,來使得左偏樹的性質得到維護。

那麼左偏樹是怎麼實現的呢?

如圖

既然叫左偏樹,那麼就比較偏向左邊嘛。所以每次加入的時候都只想改變右孩子。

我們現在要合併上面兩顆左偏樹。

1:先比較兩棵樹的根節點。發現第一棵樹比較小,所以就考慮將第二棵樹加到第一棵樹的右子樹上去。所以就遞迴的合併第二棵子樹和第一個子樹的右子樹。並且合併後的根作為1號節點的右兒子。

2:發現2號節點比4號節點小,所以1號節點的右兒子變為2,然後繼續合併2號節點的右子樹和以4為根節點的子樹。

3:發現4比5小,所以把2號節點的右兒子變為4,然後合併4號節點的右兒子和5號節點。

4:發現4號節點右兒子為空,返回

5:維護左偏樹的性質,更新每個結點的距離。並且如果左兒子的距離比右兒子要小,那麼就交換兩個兒子。

最終得到一棵這樣的左偏樹

為什麼每次都是與右兒子合併?

這時就要說到距離的用處了。既然有性質2,那麼與右兒子合併肯定比與左兒子合併更早結束遞迴(因為結束遞迴的時刻是當發現要合併的兩個節點是外節點的時候)。

操作

合併操作

上面已經說了

刪除操作

將根的左右兒子都變為零,然後將左右子樹合併起來就行了。

插入操作

插入一個幾點就相當於插入一個只有一個節點的左偏樹

例題

洛谷3377

一言

時間再拉長一點,讓我有時間收拾一下心情。 ——火影忍者