Implicit Trees and Open Edge Ends
A suffix tree is a compact trie of all suffixes. Edges store intervals into the original text rather than copied substrings: a closed interval $[l,r]$ labels $S[l\dots r]$ and has length $r-l+1$.
Ukkonen processes one symbol per phase. After phase $i$, the implicit tree represents every suffix of $S[0\dots i]$, though some suffixes may end inside edges. Every existing leaf must extend through the new symbol, so all leaves share one mutable end object. Advancing it once extends every leaf in constant time; internal edges retain fixed ends after splitting.
Appending a unique sentinel outside the alphabet forces every suffix to end at a distinct leaf, producing an explicit tree with $O(n)$ nodes and edges.
The Active Point and Remainder
The active point carries (active_node, active_edge, active_length). If the length is zero, it is an explicit node; otherwise the edge selected by the symbol at active_edge contains the point active_length symbols below that node.
remainder counts unresolved suffix extensions in the phase. It increases when a symbol arrives and decreases after leaf creation or splitting. A show-stopper can end a phase with positive remainder because those suffixes are already present implicitly.
Skip/count walks down an entire edge whenever active_length reaches its length. After an extension, root handling shortens the active string from the left; otherwise construction follows a suffix link.
At every extension, the active point denotes the longest suffix of the processed text still requiring work, and remainder counts all unresolved suffix extensions. The active point must be canonical: either active_length = 0, or it lies strictly inside its selected edge after every possible whole-edge walk-down.
Extension Rules and Suffix Links
If an explicit active node has no edge for the new symbol, create an open-ended leaf. If the active point lies inside an edge and its next symbol differs, split the edge, attach its old continuation, and add a new leaf. If the next edge symbol already equals the new symbol, increment active_length and stop the phase: the suffix is already represented.
A suffix link connects an internal node representing $x\alpha$ to the node representing $\alpha$. Internal nodes created during one phase are linked as later extensions reveal their proper suffix contexts, preventing rescans from the root.
flowchart TD
START["Pending suffix; append c"]
WALK{"Active length spans edge?"}
DOWN["Walk down edge"]
EDGE{"Outgoing c edge exists?"}
LEAF["Create open-ended leaf"]
NEXT{"Next edge symbol equals c?"}
STOP["Show-stopper: extend active length"]
SPLIT["Split edge and add leaf"]
LINK["Update pending suffix link"]
RESOLVE["Decrease remainder"]
MOVE{"Active node is root?"}
ROOTMOVE["Shorten active string"]
SUFFIX["Follow suffix link"]
START --> WALK
WALK -->|yes| DOWN
DOWN --> START
WALK -->|no| EDGE
EDGE -->|no| LEAF
EDGE -->|yes| NEXT
NEXT -->|yes| STOP
NEXT -->|no| SPLIT
LEAF --> LINK
SPLIT --> LINK
LINK --> RESOLVE
RESOLVE --> MOVE
MOVE -->|yes| ROOTMOVE
MOVE -->|no| SUFFIX
Implementation and Verification
Nodes are addressed by integer ID. The destination node owns the interval labeling its incoming edge. Internal ends are fixed integers; leaves reference the shared mutable End. A unique sentinel is selected before construction.
A leaf's suffix start is $N$ minus its root-to-leaf path length. Verification collects every leaf start, checks the complete permutation $0,\dots,N-1$ for terminated text, and compares suffix order with a naive oracle. Suffix links, skip/count, and the shared leaf end yield $O(n)$ construction for constant-time transitions over a fixed alphabet; ordered maps commonly give $O(n\log\sigma)$.