左偏樹其實是一種可並堆,它可以 o(
log2
n)o (l
og2n
)合併兩個堆。
那左偏?也就是說他左邊肯定有什麼東西比右邊大……
別著急,在左偏樹上有乙個叫距離的東西:
個點的距離,被定義為它子樹中離他最近的外節點到這個節點的距離(這與樹的深度不同)
其中我們定義乙個節點為外節點,當且僅當這個節點的左子樹和右子樹中的乙個是空節點。(注意外節點不是葉子節點)
這幅圖中的這三個節點都是外節點。
而左偏樹指的就是就是乙個節點的左兒子的距離一定大於等於右兒子的距離。
例如下面就是一棵左偏樹(藍色數字表示每個節點的距離)
乙個合格的左偏樹,滿足下列性質:
左偏樹中任意乙個節點的距離為其右兒子的距離+1+1
disti=
dist
rson
i+1 dis
ti=d
istr
soni
+1(顯然)
n n
個點的左偏樹,距離最大為lo
g(n+
1)−1
' role="presentation" style="position: relative;">log
(n+1
)−1l
og(n
+1)−
1證明還是很簡單的,考慮左偏樹根節點的距離
d d
為一定值,那麼節點數最少的情況就是乙個完全二叉樹,節點數為2d
+1−1
' role="presentation" style="position: relative;">2d+
1−12
d+1−
1。那麼n個節點的左偏樹距離也就 ≤l
og(n
+1)−
1 ≤lo
g(n+
1)−1
。既然是可並堆肯定要合併啊!
現在有兩棵左偏樹,a,
b a,b
是他們的根節點,假設va
la≤v
alb val
a≤va
lb(否則 sw
aps wa
p一下a,
b a,b
)既然v
ala≤
valb
v al
a≤va
lb,說明如果將這兩棵樹合併,根應該還是
a a
。這時,只需要遞迴合併rs
a,b' role="presentation" style="position: relative;">rsa
,brs
a,b這兩個點,知道右兒子為空,並將新樹的根節點作為rs
a rsa
。合併完成之後,di
strs
a dis
trsa
可能會變,為了保證左偏性質,如果di
stls
astrs
a dis
tlsa
strs
a,就交換
a a
的左右兒子。
最後,更新 di
sta' role="presentation" style="position: relative;">dis
tadi
sta,以
a a
為合併後的樹的根節點。
**實現:
int merge(int x,int y)
這個合併和距離有關,所以是 o(
log2
n)' role="presentation" style="position: relative;">o(l
og2n
)o(l
og2n
)相當於與乙個大小為1的堆合併。
相當於將根刪除,然後左右兒子合併。
洛谷 p3377 【模板】左偏樹(可並堆)
#include
#include
using
namespace
std;
#define lch ch[0]
#define rch ch[1]
int n,m,x,y,opt;
struct leftistv[1000005];
int find(int x)
int merge(int x,int y)
inline
int leftist::top()
inline
void leftist::pop()
int main()
}else}}
}
可並堆 左偏樹
題目描述 如題,一開始有n個小根堆,每個堆包含且僅包含乙個數。接下來需要支援兩種操作 操作1 1 x y 將第x個數和第y個數所在的小根堆合併 若第x或第y個數已經被刪除或第x和第y個數在用乙個堆內,則無視此操作 操作2 2 x 輸出第x個數所在的堆最小數,並將其刪除 若第x個數已經被刪除,則輸出 ...
可並堆 左偏樹 斜堆
經典的二叉堆已經可以在 o log n 的複雜度的情況下維護堆這樣的資料結構,也有d 堆可以維護成 o log d n 雖然pop操作的複雜度是 o d log d n 然而這兩種堆不能滿足 o log n 的合併操作,它們的經常是 o n log n 即每次將乙個堆中的堆頂拿出來放到另乙個堆裡。雖...
左偏樹 可並堆 模板
我想您應該會二叉堆吧,它包含三個操作,這裡與小根堆為例 1 查詢最小值 2 彈出最小值 3 插入乙個值 可以使用st l 的pr iori ty que ue實現,也可以用pb ds中的庫實現,當然也可以手寫反正我不會,筆者是用的系統堆 包含在庫al gori thm include include...