支配树学习笔记

一、感性理解算法

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

 

二、算法流程

1.求出图的dfs序(记录:节点所对应dfs序,dfs序所对应节点,父节点)

2.按照dfs序从大到小处理节点

(1)利用带权并查集查询每个父节点的祖先

(带权并查集https://www.cnblogs.com/fenghaoran/p/6898247.html

(2)求和祖先的sdom比较,求出该节点最小的sdom

(3)在支配树上将其与父亲连边

(4)依次处理父节点的儿子,依照以下两种方式更新

如果sdom[z]==sdom[x] 那么idom[x]=sdom[x]

否则idom[x]=idom[z] 

3.处理idom与sdom不等的残余节点

 

三、代码

洛谷 P5180 【模板】支配树

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=200005,maxm=300005;
 4 struct node{
 5     vector<int>edge[maxn];
 6     inline void add(int s,int t){
 7         edge[s].push_back(t);
 8     }
 9 }form,opp,dfs_tr,idom_tr;
10 int qfa[maxn],fa[maxn],val[maxn];
11 int ans[maxn],dfn[maxn],id[maxn],cnt;
12 int idom[maxn],sdom[maxn];
13 int n,m,s,t;
14 void dfs(int x){
15     dfn[x]=++cnt,id[cnt]=x;
16     for(int i=0;i<form.edge[x].size();i++){
17         int to=form.edge[x][i];
18         if(dfn[to])continue;
19         fa[to]=x;
20         dfs(to);
21     }
22 }
23 int find(int x){
24     if(qfa[x]==x)return x;
25     int fn=find(qfa[x]);
26     if(dfn[sdom[val[qfa[x]]]]<dfn[sdom[val[x]]])
27         val[x]=val[qfa[x]];
28     return qfa[x]=fn;
29 }
30 void tarjan(){
31     for(int x=cnt;x>=2;x--){
32         int now=id[x];
33         for(int i=0;i<opp.edge[now].size();i++){
34             int to=opp.edge[now][i];
35             if(!dfn[to])continue;
36             find(to);
37             if(dfn[sdom[val[to]]]<dfn[sdom[now]])
38                 sdom[now]=sdom[val[to]];
39         }
40         dfs_tr.add(sdom[now],now);
41         qfa[now]=fa[now];
42         now=fa[now];
43         for(int i=0;i<dfs_tr.edge[now].size();i++){
44             int to=dfs_tr.edge[now][i];
45             find(to);
46             if(sdom[val[to]]==now)idom[to]=now;
47             else idom[to]=val[to];
48         }
49     }
50     for(int i=2;i<=cnt;i++){
51         int now=id[i];
52         if(idom[now]!=sdom[now])
53             idom[now]=idom[idom[now]];
54     }
55 }
56 void dfs_ans(int x){
57     ans[x]=1;
58     for(int i=0;i<idom_tr.edge[x].size();i++){
59         int to=idom_tr.edge[x][i];
60         dfs_ans(to);
61         ans[x]+=ans[to];
62     }
63 }
64 int main(){
65     scanf("%d%d",&n,&m);
66     for(int i=1;i<=m;i++){
67         scanf("%d%d",&s,&t);
68         form.add(s,t),opp.add(t,s); 
69     }
70     for(int i=1;i<=n;i++){
71         sdom[i]=qfa[i]=val[i]=i;
72     }
73     dfs(1);
74     tarjan();
75     for(int i=2;i<=n;i++){
76         if(idom[i]){
77 //            cout<<idom[i]<<endl;
78             idom_tr.add(idom[i],i);
79         }
80     }
81     dfs_ans(1);
82     for(int i=1;i<=n;i++){
83         printf("%d ",ans[i]);
84     }
85     return 0;
86 }

洛谷 P2597[ZJOI2012]灾难

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=200005,maxm=300005;
 4 struct node{
 5     vector<int>edge[maxn];
 6     inline void add(int s,int t){
 7         edge[s].push_back(t);
 8     }
 9 }form,opp,dfs_tr,idom_tr;
10 int qfa[maxn],fa[maxn],val[maxn];
11 int ans[maxn],dfn[maxn],id[maxn],du[maxn],cnt;
12 int idom[maxn],sdom[maxn];
13 int n,m,s,t;
14 void dfs(int x){
15     dfn[x]=++cnt,id[cnt]=x;
16     for(int i=0;i<form.edge[x].size();i++){
17         int to=form.edge[x][i];
18         if(dfn[to])continue;
19         fa[to]=x;
20         dfs(to);
21     }
22 }
23 int find(int x){
24     if(qfa[x]==x)return x;
25     int fn=find(qfa[x]);
26     if(dfn[sdom[val[qfa[x]]]]<dfn[sdom[val[x]]])
27         val[x]=val[qfa[x]];
28     return qfa[x]=fn;
29 }
30 void tarjan(){
31     for(int x=cnt;x>=2;x--){
32         int now=id[x];
33         for(int i=0;i<opp.edge[now].size();i++){
34             int to=opp.edge[now][i];
35             if(!dfn[to])continue;
36             find(to);
37             if(dfn[sdom[val[to]]]<dfn[sdom[now]])
38                 sdom[now]=sdom[val[to]];
39         }
40         dfs_tr.add(sdom[now],now);
41         qfa[now]=fa[now];
42         now=fa[now];
43         for(int i=0;i<dfs_tr.edge[now].size();i++){
44             int to=dfs_tr.edge[now][i];
45             find(to);
46             if(sdom[val[to]]==now)idom[to]=now;
47             else idom[to]=val[to];
48         }
49     }
50     for(int i=2;i<=cnt;i++){
51         int now=id[i];
52         if(idom[now]!=sdom[now])
53             idom[now]=idom[idom[now]];
54     }
55 }
56 void dfs_ans(int x){
57     ans[x]=1;
58     for(int i=0;i<idom_tr.edge[x].size();i++){
59         int to=idom_tr.edge[x][i];
60         dfs_ans(to);
61         ans[x]+=ans[to];
62     }
63 }
64 int main(){
65     scanf("%d",&n);
66     for(int i=1;i<=n;i++){
67         while(1){
68             scanf("%d",&s);
69             if(s==0)break;
70             du[i]++;
71             form.add(s,i),opp.add(i,s); 
72         }
73     }
74     for(int i=1;i<=n+1;i++){
75         sdom[i]=qfa[i]=val[i]=i;
76     }
77     for(int i=1;i<=n;i++){
78         if(!du[i]){
79             form.add(n+1,i),opp.add(i,n+1);
80         }
81     }
82     dfs(n+1);
83     tarjan();
84     for(int i=1;i<=n;i++){
85         if(idom[i]){
86             idom_tr.add(idom[i],i);
87         }
88     }
89     dfs_ans(n+1);
90     for(int i=1;i<=n;i++){
91         printf("%d\n",ans[i]-1);
92     }
93     return 0;
94 } 
posted @ 2019-07-07 16:23  Robert_JYH  阅读(205)  评论(0编辑  收藏  举报