End-Position Equivalence
For substring $x$ of $S$, $\operatorname{endpos}(x)$ is the set of positions where an occurrence of $x$ ends. Two substrings are equivalent when these sets are identical. A suffix-automaton state represents one equivalence class, not one individual substring.
State $v$ stores len[v], the maximum represented length. Its suffix link targets the class containing its longest proper suffix in a different class. The state represents exactly the lengths from $\operatorname{len}(\operatorname{link}(v))+1$ through $\operatorname{len}(v)$, contributing their difference to the number of distinct substrings.
Transitions append symbols and always increase maximum length, so the automaton is a DAG. For "abb", cloning separates "b" from "ab" because their end-position sets diverge.
| State role | Represented substrings | Length interval | End positions in "abb" | Why they share a state |
|---|---|---|---|---|
| Root | Empty string | $0$ | All boundaries by convention | Initial state |
State for "a" | "a" | $[1,1]$ | $\{0\}$ | Only "a" ends at position $0$ |
Clone for "b" | "b" | $[1,1]$ | $\{1,2\}$ | Both "b" occurrences share these ends |
Original state for "ab" | "ab" | $[2,2]$ | $\{1\}$ | "ab" ends only at position $1$ |
| Final state | "bb", "abb" | $[2,3]$ | $\{2\}$ | Both end exactly at position $2$ |
Online Extension without Cloning
Maintain last, the state for the complete processed text. Appending $c$ creates current with length len[last] + 1. Follow suffix links from last, adding every missing $c$ transition to current.
If traversal passes beyond the root, link current to the root. Otherwise it stops at $p$ with transition $p\xrightarrow{c}q$. When $\operatorname{len}(p)+1=\operatorname{len}(q)$, the transition is continuous and current.link = q; state $q$ already begins at the required minimum length, so no class split is needed.
The Clone Case
If traversal finds $p\xrightarrow{c}q$ but $\operatorname{len}(p)+1\lt\operatorname{len}(q)$, the transition is non-continuous. Create a clone with length len[p] + 1, copy $q$'s transitions and suffix link, and give it zero initial occurrences. Redirect suffix-chain $c$ transitions still targeting $q$ to the clone, then link both $q$ and current to it.
The clone preserves $q$'s transition language while splitting substring-length intervals and end-position classes. During decreasing-length occurrence propagation, descendant counts flow into the clone; cloning itself creates no new text ending.
Why Clone?
Build the automaton for "abb". After "ab", the state for "ab" has maximum length $2$, and the root's b transition reaches that state.
Append the third b:
- Create
currentwith maximum length $3$ for the new prefix"abb". - Add a
btransition from the previouslasttocurrent. - Follow the suffix link to the root, whose existing
btransition reaches $q$, the former"ab"state. - The root has length $0$ and $q$ has length $2$, so $0+1\lt2$ and the transition is non-continuous.
- Create a length-$1$ clone, copy $q$'s transitions and link, redirect the root's
btransition to it, and link both $q$ andcurrentto it.
The clone now represents "b" with ends $\{1,2\}$; $q$ represents "ab" with end $\{1\}$; and current represents "bb" and "abb" with end $\{2\}$.
Implementation and Applications
Each extension creates one ordinary state and at most one clone, giving at most $2n-1$ states for non-empty text. Propagate occurrence counts from longer states to suffix-link parents: ordinary prefix states start at one, clones at zero.
Membership follows transitions. A reached state's propagated count is the occurrence count. The number of distinct substrings is $\sum_{v\ne0}(\operatorname{len}(v)-\operatorname{len}(\operatorname{link}(v)))$. DAG path counts support lexicographic selection: paths[v] is the sum of 1 + paths[u] over outgoing transitions $v\to u$.