Successor paths

For the rest of the chapter, we will focus on successor graphs. In those graphs, the outdegree of each node is 1, i.e., exactly one edge starts at each node. A successor graph consists of one or more components, each of which contains one cycle and some paths that lead to it.

Successor graphs are sometimes called functional graphs. The reason for this is that any successor graph corresponds to a function that defines the edges of the graph. The parameter for the function is a node of the graph, and the function gives the successor of that node.

$x$123456789
succ(x)357622163

defines the following graph

Since each node of a successor graph has a unique successor, we can also define a function succ(x,k) that gives the node that we will reach if we begin at node $x$ and walk $k$ steps forward. For example, in the above graph succ(4,6)=2, because we will reach node 2 by walking 6 steps from node 4:

A straightforward way to calculate a value of succ(x,k) is to start at node $x$ and walk $k$ steps forward, which takes $O(k)$ time. However, using preprocessing, any value of succ(x,k) can be calculated in only $O(\log k)$ time.

The idea is to precalculate all values of succ(x,k) where $k$ is a power of two and at most $u$, where $u$ is the maximum number of steps we will ever walk. This can be efficiently done, because we can use the following recursion:

\[ \begin{equation*} \texttt{succ}(x,k) = \begin{cases} \texttt{succ}(x) & k = 1\\ \texttt{succ}(\texttt{succ}(x,k/2),k/2) & k > 1\\ \end{cases} \end{equation*} \]

Precalculating the values takes $O(n \log u)$ time, because $O(\log u)$ values are calculated for each node. In the above graph, the first values are as follows:

$x$123456789
succ(x,1)357622163
succ(x,2)721255327
succ(x,4)327255123
succ(x,8)721255327

After this, any value of succ(x,k) can be calculated by presenting the number of steps $k$ as a sum of powers of two. For example, if we want to calculate the value of succ(x,11), we first form the representation $11=8+2+1$. Using that,

\[ \texttt{succ}(x,11)=\texttt{succ}(\texttt{succ}(\texttt{succ}(x,8),2),1) \]

For example, in the previous graph

\[ \texttt{succ}(4,11)=\texttt{succ}(\texttt{succ}(\texttt{succ}(4,8),2),1)=5 \]

Such a representation always consists of $O(\log k)$ parts, so calculating a value of succ(x,k) takes $O(\log k)$ time.