Strongly connected components collapse every mutually reachable region of a digraph into one node. Tarjan’s algorithm finds that partition in one DFS. It records when each vertex was discovered, how far an active subtree can reach back, and which vertices still belong to a component under construction.

The decisive event is a pop. When a vertex cannot reach an earlier active vertex, it is the root of one SCC; popping the stack down to that vertex emits the whole component. The canonical SCC page carries the interactive Tarjan trace and growth chart, so this focused note does not duplicate either payload.

Low-Link State

  • disc[v] is the discovery index assigned when DFS first enters v.
  • low[v] is the smallest discovery index reachable from v through DFS-tree edges plus at most one edge to a vertex still on the stack.
  • onStack[v] distinguishes an active vertex from one already assigned to a completed component.

On entry, set disc[v] = low[v] = time++ and push v. For each edge v → w, recurse when w is unvisited and then fold low[w] into low[v]. If w is already visited and still active, fold disc[w] into low[v]. After all outgoing edges, low[v] == disc[v] identifies an SCC root.

On A→B, B→C, C→A, C→D, D→E, E→D:

visit A  disc=0 low=0   stack=[A]
 visit B disc=1 low=1   stack=[A,B]
  visit C disc=2 low=2  stack=[A,B,C]
   edge C→A: low[C]=0
   visit D disc=3 low=3 stack=[A,B,C,D]
    visit E disc=4 low=4 stack=[A,B,C,D,E]
     edge E→D: low[E]=3
   D done: low[D]=disc[D]=3 -> pop {E,D}
  back in C: low[C]=min(0, low[D]=3)=0
 back in B: low[B]=min(1, low[C]=0)=0
back in A: low[A]=min(0, low[B]=0)=0
A done: low[A]=disc[A]=0 -> pop {C,B,A}

The components leave in reverse topological order of the condensation: {D, E} before {A, B, C}.

Reference Drawer

The Guard That Keeps Components Separate

The non-tree update must ignore a vertex already removed from the stack. Such an edge points into a finished component that the current DFS subtree cannot climb back through. Letting its discovery index lower low[v] can suppress a valid root and merge separate SCCs.

Tarjan’s canonical definition uses disc[w] for an edge to an active, already-visited vertex. A guarded low[w] variant still identifies the same SCC roots, but its stored values no longer have Tarjan’s formal low-link meaning. Dropping the onStack guard is the corrupting change.

This is related to the discovery/low-value pattern in articulation points and bridges, but the directed edge classification, active stack, and update rules are different.

Questions

References