前置芝士:堆
可並堆就是滿足堆性質且可以在$o(\log)$的複雜度內合併兩個堆的資料結構。常見的有斜堆,左偏樹等。
這篇文章就來介紹一下左偏樹。
首先有個問題:直接用二叉堆不香嗎?
答案是肯定的。因為二叉堆合併的時間複雜度是$o(n)$的。
所以我們有了左偏樹這個資料結構。
val:每個節點的權值,堆按這個排序。
外節點:沒有左孩子或右孩子或都沒有的節點。
dist:空節點的dist是0,外節點的dist是1,其餘節點的dist為到最近的外節點的距離。
一棵左偏樹的dist:記堆頂的dist為這課左偏樹的dist。
左偏樹顧名思義就是朝左偏的樹。它在滿足堆性質的基礎上還要滿足左孩子的dist大於等於右孩子的dist(所以左偏嘛)。
在合併時全部懟到右孩子去就可以保證在log的時間複雜度內合併了。
顯然,對於乙個非外節點的dist等於其右孩子的dist+1。
合併時左偏樹最重要的一步,我們以小根堆為例。
假設我們要合併兩個堆的堆頂分別是u,v。
於是我們為了滿足小根堆的性質找出val較小的點做為新左偏樹的頂點,這裡不妨設其為u。
於是基於啟發式合併的思想,我們把u的右孩子和v合併,遞迴去做就可以了。
因為一棵左偏樹的dist最多是$ceil(\log)$,每次合併必有一棵左偏樹的dist減1,所以這樣合併的複雜度是$o(\log+\log)$。
合併完有可能打破左偏樹的性質,要更新。
int merge(int u, intv)
直接返回堆頂即可。
合併堆頂的兩個孩子即可
注意這裡指的是給定節點,就是說告訴你了是幾號節點。左偏樹是不能快速刪除某個權值的所有節點的。
這東西沒什麼鳥用,反正我至今沒有遇到這樣的題,就不講了。其實是我太弱了。
思想和刪除堆頂類似。
像並查集一樣,每個點就是一棵左偏樹,然後再合併即可。
插入新節點同理直接合併即可。
類似於線段樹懶標記的思想,給堆頂打個標記,合併的時候再通過pushdown下放下去。
後面有一道例題。
羅馬遊戲(模板題)
monkey king(維護大根堆)
[apio2012]派遣(樹上問題)
「jloi2015」城池攻占(樹上問題+打標記)
左偏樹學習筆記
左偏樹是一種基於二叉樹的可並堆。定義乙個節點的 距離 dis xdis x disx 為它到空節點的最短路長度,左偏樹強制要求 dis lson dis rson dis ge dis dislso n d isrs on 所以 dis x di srso n 1dis x dis 1 disx d...
左偏樹 學習筆記
首先要知道左偏樹是用來幹什麼的。如果給我們兩個優先序列,然後讓我把這兩個優先佇列合併成乙個優先佇列。如果直接用堆,就是將乙個佇列裡面的數不斷彈出然後扔到另乙個佇列裡。複雜度是 o n n為佇列中數的個數。但是用左偏樹就可以做到 log n 1 n 2 ps 為了便於討論,本文所有的左偏樹均已小根樹為...
學習筆記 左偏樹
左偏樹是一種可並堆,除了堆的基本功能,最大的特點就是支援合併堆,甚至比普通堆好寫。下面敘述以小根堆為例,大根堆對稱。o log n 求乙個數所在堆的根 o 1 求最小值 o log n 合併兩個堆 o log n 刪除最小值 o log n 插入乙個數 n 是插入的總節點數 或當前堆的節點數 str...