支配树

推荐博客:

https://www.cnblogs.com/fenghaoran/p/dominator_tree.html

https://blog.csdn.net/litble/article/details/83019578

模板:

luogu5180

传送:https://www.luogu.org/problem/P5180

题意:给定一张有向图,求从1号点出发,每个点能支配的点的个数。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=3e5+10;
 4 int n,m,num,dfn[N],fa[N],pos[N],f[N],mi[N],sdom[N],idom[N],size[N]; 
 5 struct node{
 6     int to,nxt;
 7 };
 8 struct Graph{
 9     node edge[N<<1];
10     int head[N],tot;
11     void clear(){
12         tot=0;
13         for (int i=0;i<=n;i++) head[i]=-1;
14     }
15     void link(int x,int y){
16         edge[++tot]={y,head[x]};head[x]=tot;
17     }
18 }g,rg,ng,tr;
19 void init(){
20     num=0;g.clear(),rg.clear(),ng.clear(),tr.clear();
21     for(int i=1;i<=n;++i)
22         pos[i]=dfn[i]=idom[i]=fa[i]=size[i]=0,mi[i]=sdom[i]=f[i]=i;
23 }
24 void tarjan(int x){
25     dfn[x]=++num; pos[num]=x;
26     for (int i=g.head[x];i!=-1;i=g.edge[i].nxt){
27         int u=g.edge[i].to;
28         if (dfn[u]) continue;
29         fa[u]=x;
30         tarjan(u);
31     }
32 }
33 int find(int x){
34     if (x==f[x]) return x;
35     int tmp=f[x]; f[x]=find(f[x]);
36     if (dfn[sdom[mi[tmp]]]<dfn[sdom[mi[x]]]) mi[x]=mi[tmp];
37     return f[x];
38 }
39 void work(){
40     for (int i=n;i>1;i--){
41         int x=pos[i],tmp=n;
42         for (int j=rg.head[x];j!=-1;j=rg.edge[j].nxt){
43             int u=rg.edge[j].to;
44             if (!dfn[u]) continue;
45             if (dfn[u]<dfn[x]) tmp=min(tmp,dfn[u]);
46             else{
47                 find(u);
48                 tmp=min(tmp,dfn[sdom[mi[u]]]);
49             }
50         }
51         sdom[x]=pos[tmp]; f[x]=fa[x];
52         ng.link(sdom[x],x);
53         x=pos[i-1];
54         for (int j=ng.head[x];j!=-1;j=ng.edge[j].nxt){
55             int u=ng.edge[j].to;
56             find(u);
57             if (sdom[mi[u]]==sdom[u]) idom[u]=sdom[u];
58             else idom[u]=mi[u];
59         }
60     }
61     for (int i=2;i<=n;i++){
62         int x=pos[i];
63         if (idom[x]!=sdom[x]) idom[x]=idom[idom[x]];
64         tr.link(idom[x],x);
65     }
66 }
67 void calc(int x){
68     size[x]=1;
69     for (int i=tr.head[x];i!=-1;i=tr.edge[i].nxt){
70         int u=tr.edge[i].to;
71         calc(u);
72         size[x]+=size[u];
73     }
74 } 
75 void solve(){
76     tarjan(1);work();
77     calc(1); 
78     for (int i=1;i<=n;i++)
79         if (i<n) printf("%d ",size[i]);
80         else printf("%d\n",size[i]);
81 }
82 
83 int main(){
84     int x,y;
85     scanf("%d%d",&n,&m);
86     init();
87     for (int i=0;i<m;i++){
88         scanf("%d%d",&x,&y);
89         g.link(x,y); rg.link(y,x);
90     }
91     solve();
92     return 0;
93 } 
View Code

练习:

1.hdoj4694

传送:http://acm.hdu.edu.cn/showproblem.php?pid=4694

题意:从$n$点开始传送信息,问每一个点获得信息所必须经过的点的编号和为多少。

分析:是在有向图里找到关键点。考虑构建支配树,然后求解答案。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=5e4+10;
 4 const int M=1e5+10;
 5 int n,m,num,dfn[N],fa[N],pos[N],f[N],mi[N],sdom[N],idom[N],size[N]; 
 6 struct node{
 7     int to,nxt;
 8 };
 9 struct Graph{
10     node edge[M];
11     int head[N],tot;
12     void clear(){
13         tot=0;
14         for (int i=0;i<=n;i++) head[i]=-1;
15     }
16     void link(int x,int y){
17         edge[++tot]={y,head[x]};head[x]=tot;
18     }
19 }g,rg,ng,tr;
20 void init(){
21     num=0;g.clear(),rg.clear(),ng.clear(),tr.clear();
22     for(int i=1;i<=n;++i)
23         pos[i]=dfn[i]=idom[i]=fa[i]=size[i]=0,mi[i]=sdom[i]=f[i]=i;
24 }
25 void tarjan(int x){
26     dfn[x]=++num; pos[num]=x;
27     for (int i=g.head[x];i!=-1;i=g.edge[i].nxt){
28         int u=g.edge[i].to;
29         if (dfn[u]) continue;
30         fa[u]=x;
31         tarjan(u);
32     }
33 }
34 int find(int x){
35     if (x==f[x]) return x;
36     int tmp=f[x]; f[x]=find(f[x]);
37     if (dfn[sdom[mi[tmp]]]<dfn[sdom[mi[x]]]) mi[x]=mi[tmp];
38     return f[x];
39 }
40 void work(){
41     for (int i=n;i>1;i--){
42         int x=pos[i],tmp=n;
43         for (int j=rg.head[x];j!=-1;j=rg.edge[j].nxt){
44             int u=rg.edge[j].to;
45             if (!dfn[u]) continue;
46             if (dfn[u]<dfn[x]) tmp=min(tmp,dfn[u]);
47             else{
48                 find(u);
49                 tmp=min(tmp,dfn[sdom[mi[u]]]);
50             }
51         }
52         sdom[x]=pos[tmp]; f[x]=fa[x];
53         ng.link(sdom[x],x);
54         x=pos[i-1];
55         for (int j=ng.head[x];j!=-1;j=ng.edge[j].nxt){
56             int u=ng.edge[j].to;
57             find(u);
58             if (sdom[mi[u]]==sdom[u]) idom[u]=sdom[u];
59             else idom[u]=mi[u];
60         }
61     }
62     for (int i=2;i<=n;i++){
63         int x=pos[i];
64         if (idom[x]!=sdom[x]) idom[x]=idom[idom[x]];
65         tr.link(idom[x],x);
66     }
67 }
68 void calc(int x,int sum){
69     size[x]=sum+x;
70     for (int i=tr.head[x];i!=-1;i=tr.edge[i].nxt){
71         int u=tr.edge[i].to;
72         calc(u,sum+x);
73     }
74 } 
75 void solve(){
76     tarjan(n);work();
77     calc(n,0); 
78     for (int i=1;i<=n;i++)
79         if (i<n) printf("%d ",size[i]);
80         else printf("%d\n",size[i]);
81 }
82 
83 int main(){
84     int x,y;
85     while (~scanf("%d%d",&n,&m)){
86         init();
87         for (int i=0;i<m;i++){
88             scanf("%d%d",&x,&y);
89             g.link(x,y); rg.link(y,x);
90         }
91         solve();
92     };
93     return 0;
94 } 
hdoj4694

 

posted @ 2019-08-01 00:50  Changer-qyz  阅读(244)  评论(0编辑  收藏  举报