可並堆 STL pbds詳解

2021-08-07 03:39:21 字數 1238 閱讀 2990

對於堆的合併,我們首先想到的是樸素的nlogn出堆之後nlogn入堆。實質上,有一種更為高效的資料結構——可並堆。即為在保證堆頂極值的前提下實現logn的時間合併兩個堆。

與普通堆相比,左偏樹的每個結點多了乙個距離值npl(null path length)即該結點一直向右兒子走,到達空結點的距離。基於npl,我們便可以發現,交換變得有序了:在保證了左兒子npl大於右兒子npl的時候,效率有所提公升。

首先,如果左子樹為空,那麼把左右交換必然不會使右子樹變高,所以效率提高。

第二,如果左子樹的npl比較小,那麼交換後必然使右子樹的高度變小,所以效率提高。

其他方面大體和堆相同。

然而這並不是我要說的主題,萬能的c++給了我們神奇的stl,什麼可並堆統統都給你封裝好了嗎~

實現**如下

#include

#include

#include

#include

//pb_ds庫中的優先佇列,支援合併

#define lol int, less, binomial_heap_tag

using

namespace

std;

using

namespace __gnu_pbds; //使其命名空間可用

const

int maxn=1e5+5;

__gnu_pbds::priority_queueq1[maxn]; //不打前面那串會和std下的優先佇列混淆

int n,m,x,y;

int f[maxn]; //記錄是否在同一集合,並查集實現

int fd(int x)

int main()

scanf("%d",&m);

for(register

int i=1;i<=m;++i)

int xa=q1[fx].top();

q1[fx].pop();

q1[fx].push(xa/2);

int xb=q1[fy].top();

q1[fy].pop();

q1[fy].push(xb/2);

q1[fy].join(q1[fx]); //合併的關鍵操作,join函式

f[fx]=fy;

int xc=q1[fd(fx)].top();

printf("%d\n",xc);

} return

0; }

模板 可並堆

想學非旋轉的treap 然後看到裡面提到斜堆 順便學了學可並堆 可並堆 1.左偏樹 其實他介紹了4種可並堆 2.斜堆 好像說是類似平衡樹里的 splay merge a,b b.val 大根堆 merge a.r,b swap a.l,a.r 細節什麼的還有一點 大體思想是合併a和b時 先合併a的右...

左偏樹(可並堆)

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

可並堆 左偏樹

題目描述 如題,一開始有n個小根堆,每個堆包含且僅包含乙個數。接下來需要支援兩種操作 操作1 1 x y 將第x個數和第y個數所在的小根堆合併 若第x或第y個數已經被刪除或第x和第y個數在用乙個堆內,則無視此操作 操作2 2 x 輸出第x個數所在的堆最小數,並將其刪除 若第x個數已經被刪除,則輸出 ...