支配树
推荐博客:
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 }
练习:
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 }