Undirected graph
-
concept
-
time stamp
\(dfn[x] \), in depth first traversal, integer marks are made in the order in which each node is first accessed -
Retroactive value
\(low[x] \), the minimum timestamp that can be reached by a non searching edge
-
-
Edge cutting criterion
-
An undirected edge \ ((x,y) \) is a cut edge / bridge if and only if there is a child node of X satisfying \ (DFN [x] < low [y] \)
After deleting the undirected edge ((x,y)), the graph is broken into two parts -
board
-
int dfn[N], low[N], dfcnt; bool g[M]; void tarjan(int x, int ei) { dfn[x] = low[x] = ++dfcnt; for(int i = head[x]; i; i = e[i].next) { int y = e[i].t; if (!dfn[y]) { tarjan(y, i); low[x] = min(low[x], low[y]); if (dfn[x] < low[y]) g[i] = g[i^1] = 1; } else if (i != (ei^1)) low[x] = min(low[x], dfn[y]); } }
-
Cut point decision rule
-
If x is not a root node, then x is a cut point if and only if there is a child node y satisfying \ (DFN [x] \ \ Leq low [y] \)
If x is the root node, then x is the cut point if and only if there are at least two child nodes (y)_ 1,y_ 2) -
board
-
int dfn[N], low[N], dfcnt, rt; bool g[N]; void tarjan(int x) { dfn[x] = low[x] = ++dfcnt; int son = 0; for (int i = head[x]; i; i = e[i].next) { int y = e[i].t; if (!dfn[y]) { tarjan(y); low[x] = min(low[x], low[y]); if (dfn[x] <= low[y]) { son++; if (x != rt || son > 1) g[x] = 1; } } else low[x] = min(low[x], dfn[y]); } }
-
Point double connected component
-
For every double center, there is no cut point in the graph
-
board
-
int dfn[N], low[N], dfcnt, sta[N], top, cnt; vector<int> dcc[N]; bool g[N]; void tarjan(int x, int rt) { dfn[x] = low[x] = ++dfcnt; sta[++top] = x; int son = 0; for (int i = head[x]; i; i = e[i].next) { int y = e[i].t; if (!dfn[y]) { tarjan(y); low[x] = min(low[x], low[y]); if (dfn[x] <= low[y]) { son++; if (x != rt || son > 1) g[x] = 1; dcc[++cnt].clear(); while (1) { int z = sta[top--]; dcc[cnt].push_back(z); if (y == z) break; } dcc[cnt].push_back(x); } } else low[x] = min(low[x], dfn[y]); } }
-
Side double connected component
-
For an edge double, any two points have two non coincident paths
-
board
-
int dfn[N], low[N], dfcnt; bool g[M]; void tarjan(int x, int ei) { dfn[x] = low[x] = ++dfcnt; for(int i = head[x]; i; i = e[i].next) { int y = e[i].t; if (!dfn[y]) { tarjan(y, i); low[x] = min(low[x], low[y]); if (dfn[x] < low[y]) g[i] = g[i^1] = 1; } else if (i != (ei^1)) low[x] = min(low[x], dfn[y]); } } int n, m, d[N], b[N], cnt, ans; void dfs(int x) { b[x] = cnt; for(int i = head[x]; i; i = e[i].next) { int y = e[i].t; if (b[y] || g[i]) continue; dfs(y); } } int main() { //~~~ for(int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i, 0); for(int i = 1; i <= n; i++) if (!b[i]) cnt++, dfs(i); //~~~ return 0; }
Digraph
-
Strong connected components of Digraphs
-
In a strong connectivity component, if there is a path from x to y, there is a path from y to x
-
board
-
void tarjan(int x) { dfn[x] = low[x] = ++dfcnt; s[++top] = x; for(int i = head[x]; i; i = e[i].next) { int y = e[i].t; if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]); else if (!b[y]) low[x] = min(low[x], dfn[y]); } if (dfn[x] == low[x]) { cnt++; while(1) { int y = s[top--]; b[y] = cnt; size[cnt]++; if (x == y) break; } } }
Example
-
luoguP3387Contraction point
- code
#include <queue> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1e4+5, M = 1e5+5; struct side { int t, next; } e[M][2]; int head[N][2], tot[2]; void add(int x, int y, int k) { e[++tot[k]][k].next = head[x][k]; head[x][k] = tot[k]; e[tot[k]][k].t = y; } int n, m, w[N], r[N], d[N], ans; int dfn[N], low[N], dfcnt, sta[N], top, cnt, bel[N], sum[N]; void tarjan(int x) { dfn[x] = low[x] = ++dfcnt; sta[++top] = x; for (int i = head[x][0]; i; i = e[i][0].next) { int y = e[i][0].t; if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]); else if (!bel[y]) low[x] = min(low[x], dfn[y]); } if (dfn[x] == low[x]) { cnt++; while (1) { int y = sta[top--]; bel[y] = cnt; sum[cnt] += w[y]; if (x == y) break; } } } queue<int> q; int tuopu() { for (int i = 1; i <= cnt; i++) if (!r[i]) q.push(i), d[i] = sum[i]; while (!q.empty()) { int x = q.front(); q.pop(); for (int i = head[x][1]; i; i = e[i][1].next) { int y = e[i][1].t; d[y] = max(d[y], d[x] + sum[y]); if (--r[y] == 0) q.push(y); } } for (int i = 1; i <= cnt; i++) ans = max(ans, d[i]); return ans; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &w[i]); for (int i = 1; i <= m; i++) { int x, y; scanf("%d%d", &x, &y); add(x, y, 0); } for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); for (int x = 1; x <= n; x++) for (int i = head[x][0]; i; i = e[i][0].next) { int y = e[i][0].t; if (bel[x] != bel[y]) r[bel[y]]++, add(bel[x], bel[y], 1); } printf("%d\n", tuopu()); return 0; }