P5180-[模板]支配树
正題
題目鏈接:https://www.luogu.com.cn/problem/P5180
題目大意
給出nnn個(gè)點(diǎn)的一張有向圖,求每個(gè)點(diǎn)支配的點(diǎn)數(shù)量。
1≤n≤2×105,1≤m≤3×1051\leq n\leq 2\times 10^5,1\leq m\leq 3\times 10^51≤n≤2×105,1≤m≤3×105
解題思路
首先定義半支配點(diǎn)semixsemi_xsemix?表示對(duì)于點(diǎn)xxx尋找一個(gè)dfndfndfn序最小的點(diǎn)yyy滿足存在一條yyy到xxx的路徑去掉頭尾之后所有點(diǎn)的dfndfndfn序都大于xxx的。
考慮怎么求每個(gè)點(diǎn)的半支配點(diǎn),考慮兩種情況對(duì)于一個(gè)能夠直接到達(dá)xxx的點(diǎn)yyy
主要是第二種情況我們相當(dāng)于要找一個(gè)在某個(gè)點(diǎn)到根節(jié)點(diǎn)路徑上的點(diǎn)使得它的半支配點(diǎn)dfndfndfn序最小。
那么可以考慮倒序枚舉,然后用帶權(quán)并查集維護(hù)那個(gè)半支配點(diǎn)編號(hào)最小的。
之后就是半支配點(diǎn)有什么用,大概就是半支配點(diǎn)向點(diǎn)連邊那么新的圖支配關(guān)系不變。
所以一種暴力的做法就是直接跑DAGDAGDAG的支配樹(shù)求法,但是有更快的。
考慮對(duì)于一個(gè)點(diǎn)xxx和它的半支配點(diǎn)yyy,如果yyy到xxx的路徑上我們找到一個(gè)半支配點(diǎn)dfndfndfn序最小的節(jié)點(diǎn)uuu且它的半支配點(diǎn)為vvv。
那么如果
這個(gè)過(guò)程中uuu和vvv的維護(hù)和上面一樣,所以可以一起求解。
但是我們可以暫時(shí)不知道uuu的支配點(diǎn),所以可以先記錄,最后在正序的記回去。
時(shí)間復(fù)雜度O(nα(n))O(n\alpha(n))O(nα(n))
code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=2e5+10; int n,m,cnt,dfn[N],rfn[N],anc[N],ans[N]; int semi[N],idom[N],pt[N],fa[N]; vector<int>G[N],D[N],T[N]; void tarjan(int x){dfn[x]=++cnt;rfn[cnt]=x;for(int i=0;i<G[x].size();i++){int y=G[x][i];if(!dfn[y])anc[y]=x,tarjan(y);}return; } int find(int x){if(fa[x]==x)return x;int ans=find(fa[x]);if(dfn[semi[pt[fa[x]]]]<dfn[semi[pt[x]]])pt[x]=pt[fa[x]];return (fa[x]=ans); } void GetIdom(){for(int p=n;p>=2;p--){int x=rfn[p];for(int i=0;i<D[x].size();i++){int y=D[x][i];if(!dfn[y])continue;find(y);if(dfn[semi[pt[y]]]<dfn[semi[x]])semi[x]=semi[pt[y]];}fa[x]=anc[x];T[semi[x]].push_back(x);x=anc[x];for(int i=0;i<T[x].size();i++){int y=T[x][i];find(y);idom[y]=(semi[pt[y]]==x)?x:pt[y];}T[x].clear();}for(int i=2;i<=n;i++){int x=rfn[i];if(idom[x]!=semi[x])idom[x]=idom[idom[x]];}return; } int main() {scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);G[x].push_back(y);D[y].push_back(x);}for(int i=1;i<=n;i++)semi[i]=fa[i]=pt[i]=i;tarjan(1);GetIdom();for(int i=n;i>=1;i--){int x=rfn[i];ans[x]++;ans[idom[x]]+=ans[x];}for(int i=1;i<=n;i++)printf("%d ",ans[i]);return 0; }總結(jié)
以上是生活随笔為你收集整理的P5180-[模板]支配树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 电脑键盘F1到F12的正确用法如何用键盘
- 下一篇: P4428-[BJOI2018]二进制【