學習筆記 左偏樹

2022-05-08 04:54:09 字數 2465 閱讀 7850

目錄性質

操作關於建樹

一些題目

城池攻占

魔法豬學院

當且僅當這個節點的左子樹和右子樹中的乙個是空節點。

它子樹中離他最近的外節點到這個節點的距離。

首先,左偏樹保證堆性質。其次,左偏樹任一節點的左兒子的距離不小於右兒子的距離。

任一節點的距離為其右兒子的距離 \(+1\)。

\(n\) 個點的左偏樹,其最大距離不超過 \(\log n\) 級別。

如果乙個節點的距離為 \(d\),說明以它為根的子樹至少包含一棵高度為 \(d\) 的滿二叉樹。這就要求節點數至少為 \(2^d\) 級別。

假設維護大根堆,令 \(y\) 為 \(x,y\) 中權值較小的節點,將 \(y\) 與 \(x\) 的右兒子合併。返回時維護 "左兒子的距離不小於右兒子的距離",然後將 \(x\) 的距離更新。

考慮複雜度。由於 \(x,y\) 在合併時是交叉的,我們不妨定義 \(t=d_u+d_v\),其中 \(u,v\) 分別是 \(x,y\) 子樹目前合併到的點。由於每次向右兒子走,\(t\) 在一次遞迴中必定減一,而它初始時是 \(\log size_x+\log size_y\) 範圍的,所以單次合併 \(\mathcal o(\log n)\)。

int merge(int x,int y)
普通建樹是 \(\mathcal o(n\log n)\) 的,更優可以像上面這樣寫,是 \(\mathcal o(n)\) 的。

我們可以粗糙地分析一下。不妨設 \(n=2^k\)。從第二次合併開始分析:

單次合併複雜度

樹的個數

合併總複雜度

\(2\)

\(2^\)

\(2\times 2^\)

\(4\)

\(2^\)

\(4\times 2^\)

\(6\)

\(2^\)

\(6\times 2^\)

\(8\)

\(2^\)

\(8\times 2^\)

由於單次合併複雜度每次增長 \(2\),所以後面的合併總複雜度會顯著減小,大概類似於 \(2^k-1=\sum_^ 2^i\) 的分析?

支援找到左偏樹的根,然後將其刪除。首先用路徑壓縮並查集判斷是否在一棵左偏樹,但是刪除了根 \(rt\) 之後我們該如何維護呢?算出新的根,然後將 \(rt\) 的父親置為新根即可。

\(\text\)

對於每個城池維護乙個左偏樹(小根堆),用來存放可以來到這個城池的騎士(並不一定能活著出去),那麼就可以邊刪根邊統計城池的死亡騎士數和騎士到哪座城池。

關於戰鬥力的修改,把左偏樹打兩個 \(\text,\text\) 標記,因為所有操作都是自頂向下的,所以保證正確性。注意要考慮挺到最後的騎士。

一次merge()會減少乙個騎士,所以複雜度是 \(\mathcal o(m\log m)\) 的。

另外要注意的是,這題的 \(f_u\) 維護的是城池 \(u\) 對應的左偏樹的根,而不是維護父子關係。

\(\text\)

題目轉化成求第 \(k\) 短路。設反圖為 \(g'\),首先在 \(g'\) 上從 \(t\) 開始跑最短路,加入最短路上的邊,這樣就構成了一棵樹 \(t\)。不過事實上這可能不是一棵樹,我們對於點 \(v\),只需要選擇乙個為它貢獻最短路的點 \(u\) 作為它的父親即可。至於為什麼,下文會有說明。

如何構造 \(k\) 短路?乙個基本的想法是把樹邊替換成非樹邊。假設一條非樹邊 \(e(u,v)\) 連線樹上存在祖孫關係的兩點 \(u,v\)(不妨設 \(u\) 是 \(v\) 的祖先),令 \(u\) 為 \(e(u,v)\) 的初點,\(v\) 為末點,那麼就有

\[\delta_=val_-(d_v-d_u)

\]具體地,令 \(p'\) 為路徑 \(p\) 去掉樹邊的邊集。用優先佇列維護 \(\sum_\delta_e\)(它代表了 \(p'\)),每次找到最小值與其對應的終點 \(u\)(終點定義為 \(p'\) 中某條邊的起點,它滿足是 \(p'\) 中起點在 \(t\) 中 \(n\) 到 \(1\) 的那條樹上路徑中離 \(n\) 最近的點),我們可以進行兩種擴充套件:

可以用左偏樹(小根堆)來維護非樹邊的選擇,注意需要可持久化。另外這也可以解答最開始的問題:如果建出以 \(t\) 為根的樹,就可以保證擴充套件方向一定是向 \(t\) 的,而不會行進到不合法的點。

左偏樹一次合併是 \(\mathcal o(\log m)\) 的,一共有 \(n+m\) 次合併,正好和 \(\sf dijkstra\) 的複雜度一樣。點數每次合併增加 \(\log m\) 個點,所以也是可過的。

另外再說明一下為什麼merge()函式中當 \(x,y\) 有乙個為 \(0\) 時可以不新增節點:因為此時並沒有點的資訊被更改。好簡單啊可是我又想了很久。

需要注意題目要求到達 \(n\) 就結束了,所以我們要刪去 \(n\) 的所有出邊。

\(\text\)

左偏樹學習筆記

左偏樹是一種基於二叉樹的可並堆。定義乙個節點的 距離 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...