【图论】支配树
定義
支配樹(shù)一般用來(lái)求有向圖必經(jīng)點(diǎn)問(wèn)題,
即:給定起點(diǎn)S,問(wèn)對(duì)于每個(gè)點(diǎn)i,S到i的必經(jīng)點(diǎn)有哪些;
點(diǎn)i在支配樹(shù)上父親就是距離它最近的必經(jīng)點(diǎn),
顯然的,必經(jīng)點(diǎn)是具有一定傳遞性的,所以對(duì)于點(diǎn)i,S到i的所有必經(jīng)點(diǎn),就是支配樹(shù)上i到根的路徑上的所有點(diǎn)。
建樹(shù)
首先,對(duì)于一棵樹(shù),它的支配樹(shù)就是它本身;
對(duì)于一個(gè)DAG,它的支配樹(shù)也很好求,
先排拓?fù)湫?#xff0c;對(duì)于點(diǎn)i,它在支配樹(shù)上的父親就是所有能到達(dá)它的點(diǎn)在支配樹(shù)上的LCA,這個(gè)挺好理解的,
那么對(duì)于一般的有向圖呢?
先定義一些東西:dfn[x]表示x這個(gè)點(diǎn)的dfs序,
定義點(diǎn)y是點(diǎn)x的半支配點(diǎn),當(dāng)且僅當(dāng)存在一條從y到x的路徑y,v1,v2,v3....,vk,xy,v_1,v_2,v_3....,v_k,xy,v1?,v2?,v3?....,vk?,x,滿足dfn[vi]>dfn[x](1≤i≤k)dfn[v_i]>dfn[x](1\leq i \leq k)dfn[vi?]>dfn[x](1≤i≤k),這條路徑就叫它支配路徑好了(捂臉);
設(shè)semi[x]表示x的所有半支配點(diǎn)中,dfn最小的那個(gè); 顯然最小的是唯一的
(顯然的,每個(gè)點(diǎn)semi至少是它在dfs樹(shù)上的父親)
定義idom[x]表示點(diǎn)x在支配樹(shù)上的父親(距離x最近的必經(jīng)點(diǎn))
通過(guò)定義可以得出一個(gè)結(jié)論:
結(jié)論1:刪除原圖中的非樹(shù)邊(dfs樹(shù)),再添加邊(semi[x],x),支配樹(shù)依舊不變。
證明:
我們考慮對(duì)于每個(gè)點(diǎn)x,刪除它的其他入邊并加上(semi[x],x)后,對(duì)全局的影響,
對(duì)于一個(gè)點(diǎn),它的入邊分成3類(lèi):
第一種邊得到了直接的保留,不用管,
對(duì)于第二種,第三種邊,這些邊存在的意義就是提供一條路徑,使得不經(jīng)過(guò) x到根路徑上的樹(shù)邊 也能從x的某一個(gè)祖先走過(guò)來(lái),
而又因?yàn)槿绻鹹在semi[x]到x在dfs樹(shù)的路徑上(不含semi[x]),那么y一定不是x的必經(jīng)點(diǎn),也就是只要semi[x]提供了路徑就夠了,其他y沒(méi)有必要再提供,
有了這個(gè)結(jié)論就可以把一般圖轉(zhuǎn)為DAG再用上面的方法了,復(fù)雜度:O(nlog?(n))O(n\log(n))O(nlog(n))
要注意:semi不等于idom,通過(guò)semi我們只能確認(rèn)idom一定不再semi[x]~x這段樹(shù)上路徑(不含semi[x])上,對(duì)于idom是否等于semi還需要分類(lèi)討論。
關(guān)于semi怎么求請(qǐng)繼續(xù)往下看
接下來(lái)是O(n)O(n)O(n)的方法
既然我們都把semi求出來(lái)了,考慮如何用semi推出idom,
有一個(gè)顯然的結(jié)論:
結(jié)論2:對(duì)于點(diǎn)x,它到idom[x]的dfs樹(shù)上路徑中,一定不存在在路徑上的點(diǎn)y,使得 dfn[idom[y]]<dfn[idom[x]];
由此可以比較自然的再拋出一個(gè)結(jié)論:
結(jié)論3:設(shè)y為semi[x]~x樹(shù)上路徑上(不含semi[x]),dfn[idom[y]]最小的點(diǎn),則idom[x]=(dfn[semi[x]]<dfn[idom[y]])?semi[x]:idom[y];
這個(gè)證明挺顯然的,因?yàn)橐呀?jīng)轉(zhuǎn)成DAG了,歸納即可;
這個(gè)東西同理得:semi[y]是路徑上所有的semi中dfn最小的;
這樣我們就可以在得知semi后快速求出idom;
那么現(xiàn)在問(wèn)題來(lái)了,怎么求出semi?
我們?cè)O(shè)bestxbest_xbestx?表示點(diǎn)x的入邊中,出發(fā)點(diǎn)dfn最小的點(diǎn),(直接連向x的點(diǎn)中dfn最小的)
按dfn排序從大到小做,
我們做的過(guò)程相當(dāng)于每次加入一個(gè)點(diǎn)x,dfn[x]一定是當(dāng)前全局最小的,相當(dāng)于加入了一個(gè)子樹(shù)根,
(下面為了方便表示用min表示“取dfn最小的點(diǎn)”)
那么semi[x]=min?{best[y](y可以到達(dá)x)}semi[x]=\min\{best[y](y可以到達(dá)x)\}semi[x]=min{best[y](y可以到達(dá)x)}(注意這里只能走已經(jīng)加入了的點(diǎn))
同樣的semi[x]=min?{semi[y](y可以到達(dá)x)}semi[x]=\min\{semi[y](y可以到達(dá)x)\}semi[x]=min{semi[y](y可以到達(dá)x)}
同樣的semi[x]=min?{semi[y](y可以只經(jīng)過(guò)一條樹(shù)邊到達(dá)x)}semi[x]=\min\{semi[y](y可以只經(jīng)過(guò)一條樹(shù)邊到達(dá)x)\}semi[x]=min{semi[y](y可以只經(jīng)過(guò)一條樹(shù)邊到達(dá)x)}
也就是說(shuō),我們每加入一個(gè)新點(diǎn)x,設(shè)y為可以通過(guò)返祖邊直接到達(dá)x的點(diǎn),z為y~x樹(shù)上路徑上的點(diǎn),則semi[x]=min?{semi[z]}semi[x]=\min\{semi[z]\}semi[x]=min{semi[z]}
這個(gè)可以通過(guò)帶權(quán)并查集,利用其路徑壓縮的特性來(lái)做,(壓縮每個(gè)點(diǎn)到當(dāng)前根的路徑)
求出了semi那怎么求idom呢,
我們只需要找到x~semi[x]的路徑上(不含semi[x])semi的dfn最小的點(diǎn)即可,
這個(gè)相當(dāng)于詢問(wèn)一條祖先后代鏈上權(quán)值最小的點(diǎn)是哪個(gè),
和上面一樣的方案,只不過(guò)主體反過(guò)來(lái)了,我們把詢問(wèn)掛到dfn較小的那個(gè)點(diǎn)上,每次依舊是用帶權(quán)并查集維護(hù),
Code
這里給出的是CodeChef上GRAPHCNT這一題的標(biāo),
這題就是個(gè)版子題。
總結(jié)
- 上一篇: R语言RStan贝叶斯示例:重复试验模型
- 下一篇: 超好用的导航首页(最新)