日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

P5180-[模板]支配树

發(fā)布時(shí)間:2023/12/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P5180-[模板]支配树 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

正題

題目鏈接: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^51n2×105,1m3×105


解題思路

首先定義半支配點(diǎn)semixsemi_xsemix?表示對(duì)于點(diǎn)xxx尋找一個(gè)dfndfndfn序最小的點(diǎn)yyy滿足存在一條yyyxxx的路徑去掉頭尾之后所有點(diǎn)的dfndfndfn序都大于xxx的。

考慮怎么求每個(gè)點(diǎn)的半支配點(diǎn),考慮兩種情況對(duì)于一個(gè)能夠直接到達(dá)xxx的點(diǎn)yyy

  • dfny<dfnxdfn_y<dfn_xdfny?<dfnx?:那么yyy可能是xxx的半支配點(diǎn)
  • dfny>dfnxdfn_y>dfn_xdfny?>dfnx?:那么設(shè)vvv表示yyydfsdfsdfs根節(jié)點(diǎn)的路徑上的某個(gè)點(diǎn)uuudfndfndfn序最小的半支配點(diǎn),那么vvv可能是uuu的半支配點(diǎn)
  • 主要是第二種情況我們相當(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,如果yyyxxx的路徑上我們找到一個(gè)半支配點(diǎn)dfndfndfn序最小的節(jié)點(diǎn)uuu且它的半支配點(diǎn)vvv
    那么如果

  • v=yv=yv=y,那么證明整條路徑上沒(méi)有dfndfndfn序更小的半支配點(diǎn),yyy就是xxx的支配點(diǎn)。
  • du>dyd_u>d_ydu?>dy?,那么顯然uuu有更小的支配點(diǎn)支配這套路徑,所以uuu的支配點(diǎn)就是yyy的支配點(diǎn)
  • 這個(gè)過(guò)程中uuuvvv的維護(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)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。