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 }
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 }
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 }
@Author: YouSiki