仙人掌&圓方樹學習筆記

仙人掌&圓方樹學習筆記

一、仙人掌

圓方樹用來幹啥?php

——處理仙人掌的問題。html

仙人掌是啥?算法

(圖片來自於\(BZOJ1023\))網絡

——也就是任意一條邊只會出如今一個環裏面。學習

固然,若是你的圖片想看起來舒服一點,也能夠把圖片變成這樣子spa

(圖片來源於網絡)翻譯

二、DFS樹

爲啥要寫這個?--由於這個看起來也能夠解決一些仙人掌的問題。3d

對於一個仙人掌,咱們隨便構建出一棵生成樹。code

而後咱們就多了一些邊——能夠叫返祖邊,非樹邊……你想叫啥就叫啥。htm

由於每條邊只會出如今一個環中,

因此每一條返祖邊覆蓋了樹中的一條鏈,這條鏈+這條邊構成了環。

因此咱們能夠肯定每條邊都出如今了哪一個環中。

這樣子能夠解決一點點仙人掌的問題。

好比仙人掌的最大獨立集,\(dp\)的時候額外記錄一下所在環的返祖邊的端點的狀態就行了。

三、圓方樹是啥

看WC2017的營員交流的課件真的看得想死

先來定義一下什麼是圓方樹。

如下內容來自於課件:

仙人掌 \(G = (V, E)\) 的圓方樹 \(T = (V_T , E_T )\) 爲知足如下條件的無向圖:
\(V_ T = R_ T ∪ S_ T , R_ T = V, R_ T ∩ S_ T = ∅\),咱們稱$ R_ T$ 集合爲圓點、\(S_ T\)
集合爲方點
\(∀e ∈ E\),若 \(e\) 不在任何簡單環中,則 \(e ∈ E_T\)
對於每一個仙人掌中的簡單環 \(R\),存在方點 \(p_ R ∈ S_ T\) ,而且 \(∀p ∈ R\) 滿
\((p _R , p) ∈ E_ T\) ,即對每一個環建方點連全部點

據說你看完挺混亂?

我來翻譯一下:

對於一個仙人掌,它的圓方樹以下定義:

首先分爲了兩類點,一類是圓點,一類是方點。

圓點就是原仙人掌中全部的點,方點是咱們新添加進去的點。

而圓方樹的連邊規則是這樣的:

若是一條邊在仙人掌中不屬於任何一個環中,那麼它直接圓方樹中的兩個圓點。

對於仙人掌中的任意一個環,則每一個環上的點在圓方樹上對應的圓點向這個環對應的方點連邊。

如何證實圓方樹是一棵樹?

(如下內容來自於課件)

不在環上的邊在圓方樹中依然存在,

所以這些邊連通性不變;

每一個環經過新建方點的方式連成一朵菊花,連通性不變。

所以圓方樹是無向連通圖。

原圖中環的個數爲 \(|E| − |V| + 1\),則
\(|V _T | = |S _T | + |R_ T | = |V| + |E| − |V| + 1 = |E| + 1,|E _T | = |E|\)

(大小爲\(r\) 的環在仙人掌和圓方樹中都是 \(r\) 條邊),所以知足 \(|V_ T | = |E_ T | + 1\)

證實分爲了兩步:

首先證實它是聯通的。

而後就證實了點數=邊數+1

這樣就是一棵樹了。

而後讓我把課件上的一張圖片給蒯過來

好的,圓方樹就長成這個樣子啦。

四、如何構建圓方樹

我想,看了上面的東西,知道了圓方樹是啥,咱們很容易就知道怎麼構建圓方樹了吧。

首先\(Tarjan\)縮點,把每一個大小超過\(1\)的環裏面的全部點都向一個新點(方點)連邊。

而後把多出來的連接兩個圓點的邊直接給連上就行了。

彷佛真的很簡單?

五、圓方樹的性質

1.方點不會直接和方點相連

證實:

方點只會和屬於一個強連通份量的點相連,顯然不會和方點相連。

2.不管取哪一個點爲根,圓方樹的形態是同樣的

證實:

這不仍是廢話嗎?

對於一個環,咱們顯然對應的是一個方點,不管以哪一個點爲根,

這個環是不會變的,除了方點的編號不同以外就沒有任何不一樣了。

因此圓方樹是無根樹。

定義:子仙人掌

\(r\)爲根的仙人掌上的點\(p\)的子仙人掌是去除掉\(p\)\(r\)的全部簡單路徑後,\(p\)所在的聯通塊

3.以\(r\)爲根的仙人掌上\(p\)的子仙人掌就是圓方樹中以\(r\)爲根時,\(p\)子樹中的全部圓點

證實:

若是\(p\)不在環上,顯然成立。

不然,此時去除全部到達根節點的全部簡單路徑後,

剩下的只有和\(p\)相連的,而且不和\(p\)在一個環內的點

顯然是圓方樹上\(p\)子樹中的圓點(和它在一個環內的圓點都不和它直接相連了)

六、如何解決仙人掌上的一些簡單的問題

a.求仙人掌的最大獨立集(BZOJ4316)

這道題目顯然有直接用\(dfs\)樹的\(dp\)求法,見這裏

可是咱們是在學習仙人掌,因此固然要用仙人掌的方法來求解啊。

其實這裏圓方樹沒有必要出來,沒有必要區分圓點和方點。

咱們也是直接作\(dp\),可是與\(dfs\)樹不一樣的是,

咱們直接在\(Tarjan\)過程當中作\(dp\)(彷佛本質也是\(dfs\)樹?)

碰到圓圓邊(圓點和圓點直接的邊)就是普通的樹型\(dp\)進行轉移

若是是一個環上的邊的話,那麼咱們先暫時不進行操做。

當回到這個環的最上方的時候,對於這個環就行一次單獨的\(dp\)

將答案累加給環的頂端,這樣向上轉移又和樹同樣了

具體的題解戳這裏

b.求仙人掌直徑(BZOJ1023)

和普通的樹求直徑用同樣的\(dp\)就能夠了。

對於一個環,拉出來特殊考慮,用一個單調隊列維護一下。

具體的實現方法戳這裏

c.仙人掌兩點間的最短路(BZOJ2125)

構建出圓方樹(圓方樹:終於須要用到我了),直接把圓方樹樹鏈剖分(主要是用來求\(LCA\))

圓圓邊和原仙人掌是同構的,圓方邊的權值定義以下:

咱們知道方點的父親必定是圓點(轉換爲有根樹以後),

這樣子把每條圓方邊的權值賦爲到達方點父親的最短路徑就好啦。

更加詳細的題解和代碼戳這裏

這一部分的小節

前兩個問題彷佛用不到圓方樹,只須要普通的\(dp\)便可解決。實現的方法和普通的樹型\(dp\)是相似的,可是也有幾點區別:首先不是普通的\(dfs\),而是\(Tarjan\)算法的實現過程當中,順帶解決\(dp\)問題。另一個是仙人掌上的問題須要額外處理環的問題,每次找到環以後須要特殊處理。因此,解決這類問題也就是兩步:首先想好怎麼在樹上解決(圓圓邊如何解決),而後想好怎麼處理環的答案。

第三個問題就須要用到圓方樹啦,然而本質仍然是處理環和普通的樹邊之間的關係,只須要把這層關係想清楚,這一類問題應該仍是比較好解決的。

七、廣義圓方樹

前面的圓方樹只能解決仙人掌的問題。

那麼,對於一個通常的無向圖,咱們顯然也是能夠利用圓方樹來解決的(要否則我寫什麼廣義圓方樹啊?)

咱們在仙人掌中是對於每一個點雙構建一個方點,在通常圖中咱們也這麼作。

而後方點向全部點雙中的點連邊,差很少和仙人掌上的圓方樹是同樣的啦。

固然,和仙人掌上的圓方樹是有區別的啦,仙人掌上的圓方樹是圓圓點之間是可能有邊的。

那麼,廣義圓方樹呢?

先蒯張圖過來(來自\(ppl\)\(blog\))

發現了啥?

圓點和方點是相間的,怎麼搞?——強制把兩個點也當作一個點雙就行了

先找到題目來吧

帶修改,求無向圖中兩點之間全部簡單路徑上的最小權值(CF487E)

固然了,這道題目有翻譯好的版本UOJ#30,洛谷

首先咱們不考慮修改,再來想一想這道題目。

咱們既然要求的是最小值,那麼,在通過一個點雙的時候,走的必定是具備較小權值的那一側。

因此說,咱們可讓全部的方點表示它所在的點雙的最小權值,

這樣子只須要對於圓方樹樹鏈剖分以後維護鏈的最小值就好了。

好的,迴歸帶修改,無非是要動態的維護一下方點的最小權值了。

你問我怎麼動態維護若干個值的最小值?搞個\(multiset\)不就行了嗎?

可是,如今問題又來了,若是每次修改一個點的權值(這個點固然是圓點啦),

那麼,一定會修改全部和它相鄰的方點,若是是一個菊花樹,而後咱們拼命修改根節點,這樣子複雜度就起飛了。

如今讓咱們打開腦洞,大力思考一下怎麼辦?

咱們強行讓方點的權值不包括它的父親(也就是隻算它的兒子)

若是求解的時候\(LCA\)是方點,則額外計算一下方點父親的權值

這樣子每一個圓點在修改的以後只須要向上修改給父親方點啦!

因而,咱們獲得了\(Tarjan\)+圓方樹+樹鏈剖分+線段樹+\(multiset\)\(O(nlog^2n)\)的作法啦

(爲何要手寫可刪堆啊?\(multiset\)很差嗎?)

代碼和題解

八、完結撒花

呼,終於寫完啦。

最後再來總的說一說仙人掌和圓方樹。

對於仙人掌,咱們對應的圓方樹惟一。

不管是廣義圓方樹仍是普通的圓方樹,和普通的樹相比,惟一的區別就是要額外考慮方點的貢獻。

總的來講,就是碼農+思惟題啦,只要想清楚方點的處理,一切都很好辦了。

相關文章
相關標籤/搜索