左偏樹 可並堆 學習筆記

2021-08-20 21:23:35 字數 2368 閱讀 7956

學習左偏樹 || 可並堆,先從名字上理解

可並堆,從字面意思上理解就知道是可以快速合併的堆

左偏樹,也不難想到意為整個堆是向左偏的,即堆的左子樹距離要大於等於右子樹

那麼為什麼可並會和左偏聯絡在一起呢

我們可以模擬平衡樹的啟發式合併

即每次把節點總數小的一棵樹合併到節點總數大的一棵樹

左偏樹 || 可並堆 也就是利用了這一點思想

每次合併的時候都往節點總數比較小的右子樹合併

以便大大降低插入總複雜度

左偏樹 || 可並堆—基本概念&&性質

學習 左偏樹 || 可並堆 前先了解幾個概念和性質

節點的距離

注意到上面解釋左偏的時候說的是

堆的左子樹距離要大於右子樹

而不是左子樹深度要大於右子樹

也就是說距離和深度是不一樣的

距離,表示該節點到它子樹裡面最近的葉子節點的路徑長 (葉子節點距離為0)

距離這個概念就是實現左偏樹的關鍵

左偏樹 || 可並堆 又與距離相關的區別於普通堆的幾個性質

1.節點的左兒子的距離大於等於右兒子的距離

就是上面提到的利用了啟發式合併的思想

這樣每次合併都往右子樹合併就會快很多

2.任意節點的距離等於其右兒子的距離+1

根據距離的定義不難證明

3.乙個n個節點的左偏樹距離最大為lo

g(n+

1)−1lo

g(n+

1)−1

蒟蒻暫時還不會證明=_=

左偏樹 || 可並堆—合併

假設要合併的兩個堆為x和y

我們假設va

l[x]

l[y]

v al

[x

]

l[y]

然後將y往x的右子樹插入

插入後新樹的右子樹距離可能會變大

破壞了性質1

所以這時候要交換左右子樹

然後更新根節點距離就好

int merge(int x,int y)

根據性質3,整個合併過程複雜度上界為o(

log(

nx+1

)+lo

g(ny

+1))

o (l

og(n

x+1)

+log

(ny+

1)

)左偏樹 || 可並堆—刪除

直接合併堆頂的左子樹和右子樹就好

複雜度o(l

ogn)

o (l

ogn)

void pop(int x)

左偏樹 || 可並堆—模板題

p3377 【模板】左偏樹(可並堆)

合併操作要並查集維護堆頂(樹根)

#include

#include

#include

#include

#include

#include

using namespace std;

intread()

while(ss>='0'&&ss<='9')

return

x*f;

}const int maxn=100010;

int n,m;

int ch[maxn][2],fa[maxn];

int val[maxn],dis[maxn];

int merge(int

x,int

y)int find(int

x)void pop(int

x)int main()

else

int fx=find(x);

printf("%d\n",val[fx]);

pop(fx);}}

return

0;}

左偏樹(可並堆)

左偏樹其實是一種可並堆,它可以 o log2 n o l og2n 合併兩個堆。那左偏?也就是說他左邊肯定有什麼東西比右邊大 別著急,在左偏樹上有乙個叫距離的東西 個點的距離,被定義為它子樹中離他最近的外節點到這個節點的距離 這與樹的深度不同 其中我們定義乙個節點為外節點,當且僅當這個節點的左子樹和...

可並堆 左偏樹

題目描述 如題,一開始有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 即每次將乙個堆中的堆頂拿出來放到另乙個堆裡。雖...