學習左偏樹 || 可並堆,先從名字上理解
可並堆,從字面意思上理解就知道是可以快速合併的堆
左偏樹,也不難想到意為整個堆是向左偏的,即堆的左子樹距離要大於等於右子樹
那麼為什麼可並會和左偏聯絡在一起呢
我們可以模擬平衡樹的啟發式合併
即每次把節點總數小的一棵樹合併到節點總數大的一棵樹
左偏樹 || 可並堆 也就是利用了這一點思想
每次合併的時候都往節點總數比較小的右子樹合併
以便大大降低插入總複雜度
左偏樹 || 可並堆—基本概念&&性質
學習 左偏樹 || 可並堆 前先了解幾個概念和性質
節點的距離:
注意到上面解釋左偏的時候說的是
堆的左子樹距離要大於右子樹
而不是左子樹深度要大於右子樹
也就是說距離和深度是不一樣的
距離,表示該節點到它子樹裡面最近的葉子節點的路徑長 (葉子節點距離為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
所以這時候要交換左右子樹
然後更新根節點距離就好
根據性質3,整個合併過程複雜度上界為o(int merge(int x,int y)
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 即每次將乙個堆中的堆頂拿出來放到另乙個堆裡。雖...