P3377 模板 左偏樹(可並堆)

2022-06-18 02:24:09 字數 2067 閱讀 9233

如題,一開始有 nn 個小根堆,每個堆包含且僅包含乙個數。接下來需要支援兩種操作:

1 x y:將第 xx 個數和第 yy 個數所在的小根堆合併(若第 xx 或第 yy 個數已經被刪除或第 xx 和第 yy 個數在用乙個堆內,則無視此操作)。

2 x:輸出第 xx 個數所在的堆最小數,並將這個最小數刪除(若有多個最小數,優先刪除先輸入的;若第 xx 個數已經被刪除,則輸出 -1−1 並無視刪除操作)。

左偏樹byhsfzzh1

左偏樹是一種支援在o(logn*logn)的時間複雜度內進行合併的堆式資料結構

一些定義:

外節點:左兒子或右兒子是空節點的節點

距離:乙個節點的距離d[x]定義為其子樹中與節點x最近的外節點到x的距離,特別的,定義空節點的距離為-1。

左偏樹的基本性質:

具有堆的性質。

具有左偏性質,即對於每個節點x,有d[l]>d[r]。

基本結論:

(1)節點x的距離d(x) = d(rc) + 1

(2)距離為n的左偏樹至少有2^(n+1)-1個節點,此時該左偏樹的形態是一顆滿二叉樹。

(3)有n個節點的左偏樹的根節點的距離是o(logn)的。

合併操作:

左偏樹最基本的操作是合併操作。

定義merge(x,y)為合併兩顆分別以xy為根節點的左偏樹。其返回值為合併之後的根節點。

首先不考慮左偏性質,我們描述一下合併兩個具有堆性質的樹的過程。假設我們要合併的是小根堆。

(1)若vx<=vy,以x作為合併後的根節點,否則以y作為合併後的根節點。

(2)將y與x的其中乙個兒子合併,用合併後的根節點代替與y合併的兒子的位置,並返回x。

(3)重複以上操作。如果x和y中有乙個為空節點,返回x+y。

令h為樹高,每次合併都減少1,上述操作的時間複雜度是o(h)的。

當要合併的樹退化成一條鏈的時候,這樣做的複雜度是o(n)的。

要使時間複雜度更優,就要使樹合併得更平衡。我們有兩種方式:

(1)每次隨機選擇x的左右兒子進行合併。(很像treap)。

(2)左偏樹。

由於左偏樹中左兒子的距離大於右兒子的距離,我們每次將y與x的右兒子合併。

由於左偏樹的樹高是logn的,所以單次合併的時間複雜度也是logn的。

但是,兩顆左偏樹按照上述方法合併後,可能不再保持左偏樹的左偏性質,在每次合併完後,判斷對節點x是否有d(lc)>d(rc)。若沒有,則交換lc,rc,並維護x的距離d(x) = d(rc) + 1。

插入給定值:

新建乙個值等於插入值的節點,將該節點和左偏樹合併即可。時間複雜度o(logn)。

求最小值:

由於左偏樹的堆性質,左偏樹上的最小值為其根節點的值。

刪除最小值:

等價於刪除左偏樹的根節點,合併根節點的左右兒子即可。

#includeusing

namespace

std;

const

int maxn=1e5+100

;int

n,m,op,x,y;

intlc[maxn];

intrc[maxn];

intd[maxn];

intfather[maxn];

bool

tf[maxn];

struct

left_tree

}a[maxn];

int findfather (int

x)

returnx;}

int merge (int x,int

y) int

main ()

if (op==2

) x=findfather(x);

printf(

"%d\n

",a[x].v);

tf[x]=1

; father[lc[x]]=father[rc[x]]=father[x]=merge(lc[x],rc[x]);

lc[x]=rc[x]=d[x]=0

; }

}}

P3377 模板 左偏樹 可並堆

開始時n nn個只有乙個數的集合,要求支援 合併兩個集合 查詢乙個集合中的最小值並刪除 左偏樹就是維護乙個滿足以下性質的樹 對於v al xval x valx 有val x llsx val xva lx llsx 且v al x lrsx val xva lx lrsx 對於任何節點有左子樹的深...

P3377 模板 左偏樹(可並堆)

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

P3377 模板 左偏樹(可並堆)

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