Diary - 2024.12.05

rizynvu發表於2024-12-05

哥我真的佩服你了,,,
你說物理老師上完課說的給一兩天整理的意思又沒有可能是指拿時間整理一下然後等老師來講,
而不是做完作業直接開跑看課,然後讓大家追趕你的步伐,,,
有點流汗了,感覺現在一天學了好多腦子要爆掉了,然後我還得快點做作業來跟上你看課的速度,,,

哥我錯了,我是菜比行嗎,,,

在您的引領之下,僅用四天就把物理補完了開始要回去上物理課了。
甚至是隻回去上物理,有點搞笑了。

但是又要回班上了,我要玉玉了。


實際上 boruvka 是十分優美的一個東西。

雖然往往只直接把複雜度當作 \(\mathcal{O}(f(n, m)\log n)\)\(f(n, m)\) 通常就是一個關於 \(n, m\) 的多項式,視題目及做法而定),但是還是要考慮下為什麼的。
這是因為在最劣情況下如果每次找最小邊都是雙向邊,所以才會使得每次連通塊數 \(/ 2\) 的,輪數 \(\mathcal{O}(\log n)\)

但是實際上拋棄死板的複雜度,從每一步去入手能得到更優美的性質。
其實也就是去深究一下每一步縮連通塊的情況。

例題:Codeforces 2041N(口胡還在發力)。

這種差不多的完全圖,肯定是還要考慮下 boruvka 的。
然後分析 boruvka 第一輪點 \(i\) 找到的對應的最短邊 \((i, j)\)\(j\) 的性質。
那麼因為邊權是 \(a_i + a_j\) 的形式,那就是要最小化 \(a_j\)
定義 \(S_i = \{1, 2, \cdots, n\} - \{j | (i, j)\in E\} - \{i\}\)\(E\) 為被刪掉的邊集),那麼 \(j\) 肯定滿足 \(j\in S_i, a_j = \min_{k\in S_i}(a_k)\)

於是一個直觀的過程就是先按 \(a_i\) 從小到大排序。
對於每一個 \(i\)\(j = 1\) 開始往後掃,直到 \(j\not = i, (i, j)\not \in S\),那麼第一輪的連邊就是 \((i, j)\)

這個時候令 \(b_i = j - 1\),那麼應當有 \(\sum\limits_{i = 1}^n b_i\le |S| = m\),那麼這說明了暴力掃的複雜度是對的(均攤)且 \(b_i\) 只會有 \(\mathcal{O}(\sqrt m)\) 種本質不同值。
(實際上有點小問題,因為忽略掉了 \(i = j\) 時憑空多出的一條被刪的邊,但是實際上這個情況也只會出現 \(\mathcal{O}(\sqrt{m})\) 次,是 \(\mathcal{O}(\sqrt{m + \sqrt m})\),但是直接分析成 \(\mathcal{O}(\sqrt{n + m})\) 問題也不大。)

那麼這說明了在第一輪的縮點後,實際上的連通塊只會有 \(\mathcal{O}(\sqrt m)\) 個(連通塊應當關於 \(b_i\) 是個類菊花的樣子,\(b_i\) 為根),而且 \(\operatorname{deg}_i > 1\) 的點此時只會有 \(\sqrt{m}\) 個。

於是說在後面的 \(\mathcal{O}(\sqrt{m})\) 個連通塊間跑出的最小生成樹也只會有 \(\mathcal{O}(\sqrt{m})\) 條邊,那麼在這一階段產生的 \(\operatorname{deg}_i > 1\) 的點的數量也是 \(\mathcal{O}(\sqrt m)\) 級別的。

於是整合起來,\(\operatorname{deg}_i > 1\) 的點的數量是 \(\mathcal{O}(\sqrt m)\) 的。

那麼對於 \(\operatorname{deg}_i = 1\) 的葉子,最小生成樹內刪掉了對樹的形態沒有影響。
於是只需要對於 \(\mathcal{O}(\sqrt m)\) 個非葉子的點直接刪掉重新跑一遍最小生成樹就行了。

當然這只是大體思路,還需要討論下細節問題。

Q:如何 \(\mathcal{O}(n + m)\) 求最小生成樹?
首先第一輪的 boruvka 找最小值是 \(\mathcal{O}(n + m)\) 的,排序可以用基數排序做到 \(\mathcal{O}(n)\),後面的連邊可以在最後連出的環找一下環上最大權邊,斷掉即可,也是 \(\mathcal{O}(n)\) 的(實際上想直接用並查集 \(\alpha(n)\) 應該也是可以的吧)。
那麼對於後面 \(\mathcal{O}(\sqrt m)\) 個連通塊的最小生成樹只需要在 \(\mathcal{O}(n + m)\) 內找到兩兩連通塊間的最小邊權,然後跑 \(\mathcal{O}(n^2 + m)\) 的 prim 就可以了(這裡的 \(n, m\) 指的是縮完連通塊的圖的點數邊數,所以複雜度應是 \(\mathcal{O}(m)\) 的)。

Q:那如何 \(\mathcal{O}(n + m)\) 找到兩兩連通塊間的最小邊權。
好問題……
首先可以在塊內先按 \(a_i\) 排好序。
首先一個暴力的想法是對於每個點都找一下每個連通塊的最小值,這個依然均攤分析到 \(\mathcal{O}(n + m)\)
最後在連通塊內合併資訊,但是這樣就 \(\mathcal{O}(m\sqrt{m})\) 了……
考慮到塊內其實還是有很多資訊是無用的。
考慮直接列舉兩個塊,讓其中一個塊 \(a_i\) 從小到大遍歷 \(i\),那麼對應在另一個塊找到於其的最小權 \(a_j\)
注意到的是因為 \(a_i\) 不降,那麼如果第一個塊後面才列舉到的 \(a_k\ge a_i\),實際上在第二個塊列舉到 \(j\) 之前就可以了,因為 \(a_k + a_j\ge a_i + a_j\)\(j\) 往後還更大。
實際上一個更偷懶的想法是如果找到 \(a_i\) 能和第二個塊的最小值連邊就直接不往後列舉了,正確性顯然,就是上面說到的弱化。
考慮分析複雜度,那麼可以拆分為,跳過(被刪掉)的邊數 + 在第一個塊遍歷到的點數(對於這些點確定一條邊出來)。
那麼被跳過的邊肯定是不超過 \(m\) 條的。
對於遍歷到的點數,拆分成,字首不能與另一個塊最小值有連邊的點數 + 與另一個塊最小值有連邊的點數。
對於第一部分,依然是均攤分析被跳過的邊,是 \(\mathcal{O}(m)\) 的;對於第二部分,兩個連通塊間只會存在一次,因為連通塊數是 \(\mathcal{O}(\sqrt{m})\) 的,最後也是 \(\mathcal{O}(m)\) 的。

於是最後時間複雜度 \(\mathcal{O}((n + m)\sqrt{m})\),看起來好像就完結撒花了/慶祝。
實際上實現可能還是有點難度的,加上我是口胡哥,就沒有程式碼了。

byd 差點給刪了,嚇死我了。

但是我嚴重懷疑這題是那位 tmt514 出的。
直接 boruvka 就搜到過他的文章(其實是 boruvka 分治,但是我現在都還沒看)。
而且裡面有個專門的最小生成樹板塊。
而且裡面還有個 Borůvka-Prim 演演算法 感覺就是和這題大致過程一樣,先 boruvka 在 prim 阿。
參考連結:https://tmt514.github.io/algorithm-analysis/minimum-spanning-tree/boruvka-prim.html


突然發現似乎我的擺都是因為記性不好。