Dominator Tree & Lengauer-Tarjan Algorithm

问题描述

给出一张有向图,可能存在环,对于所有的i,求出从1号点到i点的所有路径上的必经点集合。

 

什么是支配树

两个简单的小性质——

1.如果i是j的必经点,而j又是k的必经点,则i也是k的必经点。

2.如果i和j都是k的必经点,则i和j之间必然存在必经点关系,不可能互相都不是必经点。

 

不难发现所有的必经点关系形成了一个以1点为根的树形关系,每个点的支配点集合就是其到根节点(1点)路径上的点集,称这棵树为支配树。

 

怎么求支配树

假如我们得到的是一个有向无环图,那么只需要$O(N)$的做一遍拓扑排序就可以了,非常简单。

假如我们得到了一张有向有环图,那么我们可以$O(N)$的枚举一个点,把它从图上删去,从根$O(M)$的DFS(或BFS)一次,就可以知道它是哪些点的必经点,复杂度$O(NM)$,简单粗暴,但时间复杂度难以接受。

然后就有了Lengauer-Tarjan算法,复杂度为$O(NlogN)$,有一堆定理证明,想详细的搞明白最好去看Tarjan的英文论文,网上有些中文翻译难免带些小错误。

 

简单的上手题

据某位大佬说,这个算法还没见到过不是裸题的题…… OTZ

不过确实,目前这个算法一般应用在浅层,题面也是非常的裸,简直就是再说“快来拿支配树上我啊!”

 

CodeChef Counting on a directed graph GRAPHCNT

  1 #include <bits/stdc++.h>
  2  
  3 using namespace std;
  4  
  5 typedef long long lnt;
  6  
  7 const int mxn = 100005;
  8  
  9 int n, m;
 10  
 11 int tim;
 12 int dfn[mxn];
 13 int idx[mxn];
 14 int fat[mxn];
 15 int idm[mxn];
 16 int sdm[mxn];
 17 int anc[mxn];
 18 int tag[mxn];
 19 lnt siz[mxn];
 20 lnt son[mxn];
 21  
 22 vector<int> G[mxn];
 23 vector<int> R[mxn];
 24 vector<int> S[mxn];
 25 vector<int> T[mxn];
 26  
 27 void dfsG(int u)
 28 {
 29     idx[dfn[u] = ++tim] = u;
 30     
 31     for (auto v : G[u])if (!dfn[v])
 32         fat[v] = u, dfsG(v);
 33 }
 34  
 35 void dfsT(int u)
 36 {
 37     siz[u] = 1;
 38     
 39     for (auto v : T[u])
 40         dfsT(v), siz[u] += siz[v];
 41 }
 42  
 43 int find(int u)
 44 {
 45     if (u == anc[u])
 46         return u;
 47     
 48     int r = find(anc[u]);
 49     
 50     if (dfn[sdm[tag[anc[u]]]] < dfn[sdm[tag[u]]])
 51         tag[u] = tag[anc[u]];
 52     
 53     return anc[u] = r;
 54 }
 55  
 56 signed main(void) 
 57 {
 58     cin >> n >> m;
 59     
 60     for (int i = 1, u, v; i <= m; ++i)
 61     {
 62         cin >> u >> v;
 63         G[u].push_back(v);
 64         R[v].push_back(u);
 65     }
 66     
 67     for (int i = 1; i <= n; ++i)
 68         sdm[i] = tag[i] = anc[i] = i;
 69     
 70     dfsG(1);
 71     
 72     for (int i = tim; i > 1; --i)
 73     {
 74         int u = idx[i];
 75         
 76         for (auto v : R[u])if (dfn[v])
 77         {
 78             find(v);
 79             if (dfn[sdm[tag[v]]] < dfn[sdm[u]])
 80                 sdm[u] = sdm[tag[v]];
 81         }
 82         
 83         anc[u] = fat[u];
 84         
 85         S[sdm[u]].push_back(u);
 86         
 87         int t = idx[i - 1];
 88         
 89         for (auto v : S[t])
 90         {
 91             find(v);
 92             if (sdm[tag[v]] == t)
 93                 idm[v] = t;
 94             else
 95                 idm[v] = tag[v];
 96         }
 97         
 98         S[t].clear();
 99     }
100     
101     for (int i = 2; i <= tim; ++i)
102     {
103         int u = idx[i];
104         if (idm[u] != sdm[u])
105             idm[u] = idm[idm[u]];
106     }
107     
108     for (int i = 2; i <= tim; ++i)
109         T[idm[i]].push_back(i);
110     
111     dfsT(1);
112     
113     lnt ans = tim * (tim - 1);
114     
115     for (int i = tim, u; i >= 2; --i)
116     {
117         ++son[u = idx[i]];
118         if (idm[u] != 1)
119             son[idm[u]] += son[u];
120         else
121             ans -= son[u] * (son[u] - 1);
122     }
123     
124     ans >>= 1;
125     
126     cout << ans << endl;
127 } 
View Code

 

HDU 4694 Important Sisters

  1 #include <cstdio>
  2 #include <cstring>
  3 
  4 #define mxn 50005
  5 #define mxm 200005
  6 #define lnt long long
  7 
  8 int n, m;
  9 
 10 struct Lin {
 11     int tt;
 12     int hd[mxn];
 13     int nt[mxm];
 14     int to[mxm];
 15     
 16     void init(void) {
 17         memset(hd, 0, sizeof hd), tt = 0;
 18     }
 19     
 20     void adde(int u, int v) {
 21         nt[++tt] = hd[u], to[tt] = v, hd[u] = tt;
 22     }
 23 }G, R, T, S;
 24 
 25 int tim;
 26 int idx[mxn];
 27 int dfn[mxn];
 28 int fat[mxn];
 29 int anc[mxn];
 30 int tag[mxn];
 31 int sdm[mxn];
 32 int idm[mxn];
 33 lnt ans[mxn];
 34 
 35 void dfsG(int u) {
 36     idx[dfn[u] = ++tim] = u;
 37     
 38     for (int i = G.hd[u], v; i; i = G.nt[i])
 39         if (!dfn[v = G.to[i]])dfsG(v), fat[v] = u;
 40 }
 41 
 42 void dfsT(int u) {
 43     ans[u] += u;
 44     
 45     for (int i = T.hd[u], v; i; i = T.nt[i])
 46         ans[v = T.to[i]] += ans[u], dfsT(v);
 47 }
 48 
 49 int find(int u) {
 50     if (anc[u] == u)return u;
 51     
 52     int r = find(anc[u]);
 53     
 54     if (dfn[sdm[tag[anc[u]]]] < dfn[sdm[tag[u]]])
 55         tag[u] = tag[anc[u]];
 56         
 57     return anc[u] = r;
 58 }
 59 
 60 signed main(void) 
 61 {
 62     while (scanf("%d%d", &n, &m) != EOF) {
 63         memset(ans, 0, sizeof ans);
 64         memset(dfn, 0, sizeof dfn), tim = 0;
 65         
 66         G.init(); R.init(); T.init(); S.init();
 67         
 68         for (int i = 1, u, v; i <= m; ++i)
 69             scanf("%d%d", &u, &v), G.adde(u, v), R.adde(v, u);
 70             
 71         for (int i = 1; i <= n; ++i)
 72             sdm[i] = tag[i] = anc[i] = i;
 73         
 74         dfsG(n);
 75         
 76         for (int i = tim; i > 1; --i) {
 77             int u = idx[i], v;
 78             
 79             for (int j = R.hd[u]; j; j = R.nt[j])
 80                 if (dfn[v = R.to[j]]) {
 81                     find(v);
 82                     if (dfn[sdm[tag[v]]] < dfn[sdm[u]])
 83                         sdm[u] = sdm[tag[v]];
 84                 }
 85                 
 86             anc[u] = fat[u]; S.adde(sdm[u], u); u = idx[i - 1];
 87             
 88             for (int j = S.hd[u]; j; j = S.nt[j]) {
 89                 find(v = S.to[j]);
 90                 if (sdm[tag[v]] == u)
 91                     idm[v] = u;
 92                 else
 93                     idm[v] = tag[v];
 94             }
 95         }
 96         
 97         for (int i = 2; i <= tim; ++i) {
 98             int u = idx[i];
 99             if (idm[u] != sdm[u])
100                 idm[u] = idm[idm[u]];
101             T.adde(idm[u], u);
102         }
103         
104         dfsT(n);
105         
106         for (int i = 1; i < n; ++i)
107             printf("%lld ", ans[i]);
108             
109         printf("%lld\n", ans[n]);
110     }
111 }
View Code

 

SPOJ BIA - Bytelandian Information Agency

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 const int mxn = 5005;
  6 const int mxm = 200005;
  7 
  8 int n, m;
  9 
 10 vector<int> G[mxn];
 11 vector<int> R[mxn];
 12 vector<int> S[mxn];
 13 
 14 inline void init(vector<int> v[mxn])
 15 {
 16     for (int i = 0; i < mxn; ++i)
 17         v[i].clear();
 18 }
 19 
 20 int tim;
 21 int dfn[mxn];
 22 int idx[mxn];
 23 int fat[mxn];
 24 int idm[mxn];
 25 int sdm[mxn];
 26 int anc[mxn];
 27 int cnt[mxn];
 28 int tag[mxn];
 29 
 30 void dfsG(int u)
 31 {
 32     idx[dfn[u] = ++tim] = u;
 33     
 34     for (auto v : G[u])if (!dfn[v])
 35         fat[v] = u, dfsG(v);
 36 }
 37 
 38 int find(int u)
 39 {
 40     if (anc[u] == u)
 41         return u;
 42     
 43     int r = find(anc[u]);
 44     
 45     if (dfn[sdm[tag[anc[u]]]] < dfn[sdm[tag[u]]])
 46         tag[u] = tag[anc[u]];
 47     
 48     return anc[u] = r;
 49 }
 50 
 51 signed main(void) 
 52 {
 53     while (cin >> n >> m)
 54     {
 55         init(G);
 56         init(R);
 57         init(S);
 58         
 59         tim = 0;
 60         
 61         memset(cnt, 0, sizeof cnt);
 62         memset(dfn, 0, sizeof dfn);
 63         
 64         for (int i = 1, u, v; i <= m; ++i)
 65         {
 66             cin >> u >> v;
 67             G[u].push_back(v);
 68             R[v].push_back(u);
 69         }
 70         
 71         for (int i = 1; i <= n; ++i)
 72             sdm[i] = tag[i] = anc[i] = i;
 73         
 74         dfsG(1);
 75         
 76         for (int i = tim; i > 1; --i)
 77         {
 78             int u = idx[i];
 79             
 80             for (auto v : R[u])if (dfn[v])
 81             {
 82                 find(v);
 83                 if (dfn[sdm[tag[v]]] < dfn[sdm[u]])
 84                     sdm[u] = sdm[tag[v]];
 85             }
 86             
 87             anc[u] = fat[u];
 88             
 89             S[sdm[u]].push_back(u);
 90             
 91             u = idx[i - 1];
 92             
 93             for (auto v : S[u])
 94             {
 95                 find(v);
 96                 
 97                 if (sdm[tag[v]] == u)
 98                     idm[v] = u;
 99                 else
100                     idm[v] = tag[v];
101             }
102             
103             S[u].clear();
104         }
105         
106         for (int i = 2; i <= tim; ++i)
107         {
108             int u = idx[i];
109             if (idm[u] != sdm[u])
110                 idm[u] = idm[idm[u]];
111         }
112         
113         for (int i = 2; i <= tim; ++i)
114             ++cnt[idm[i]];
115             
116         int ans = 0;
117         
118         for (int i = 1; i <= tim; ++i)
119             if (cnt[i])++ans;
120         
121         cout << ans << endl;
122         
123         for (int i = 1; i <= tim; ++i)
124             if (cnt[i])cout << i << " ";
125         
126         cout << endl; 
127     }
128 }
View Code

 

Useful Roads

 

@Author: YouSiki

 

posted @ 2017-03-10 08:19  YouSiki  阅读(447)  评论(0编辑  收藏  举报