Improve language

This commit is contained in:
Antti H S Laaksonen 2017-05-29 21:23:47 +03:00
parent d4b4bb6708
commit c8ed23c39e
1 changed files with 38 additions and 69 deletions

View File

@ -3,14 +3,14 @@
\index{tree query}
This chapter discusses techniques for
processing queries related
to subtrees and paths of a rooted tree.
processing queries on
subtrees and paths of a rooted tree.
For example, such queries are:
\begin{itemize}
\item what is the $k$th ancestor of a node?
\item what is the sum of values in the subtree of a node?
\item what is the sum of values in a path between two nodes?
\item what is the sum of values on a path between two nodes?
\item what is the lowest common ancestor of two nodes?
\end{itemize}
@ -21,11 +21,10 @@ For example, such queries are:
The $k$th \key{ancestor} of a node $x$ in a rooted tree
is the node that we will reach if we move $k$
levels up from $x$.
Let $f(x,k)$ denote the $k$th ancestor of a node $x$
Let $\texttt{ancestor}(x,k)$ denote the $k$th ancestor of a node $x$
(or $0$ if there is no such an ancestor).
For example, in the following tree, $f(2,1)=1$, $f(8,2)=4$
and $f(5,2)=0$.
For example, in the following tree,
$\texttt{ancestor}(2,1)=1$ and $\texttt{ancestor}(8,2)=4$.
\begin{center}
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (0,3) {$1$};
@ -49,17 +48,17 @@ and $f(5,2)=0$.
\end{tikzpicture}
\end{center}
An easy way to calculate the value of $f(x,k)$
An easy way to calculate any value of $\texttt{ancestor}(x,k)$
is to perform a sequence of $k$ moves in the tree.
However, the time complexity of this method
is $O(k)$, which may be slow, because a tree of $n$
nodes may have a chain of $n$ nodes.
Fortunately, using a technique similar to that
used in Chapter 16.3, any value of $f(x,k)$
used in Chapter 16.3, any value of $\texttt{ancestor}(x,k)$
can be efficiently calculated in $O(\log k)$ time
after preprocessing.
The idea is to precalculate all values $f(x,k)$
The idea is to precalculate all values $\texttt{ancestor}(x,k)$
where $k \le n$ is a power of two.
For example, the values for the above tree
are as follows:
@ -68,16 +67,16 @@ are as follows:
\begin{tabular}{r|rrrrrrrrr}
$x$ & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 \\
\hline
$f(x,1)$ & 0 & 1 & 4 & 1 & 1 & 2 & 4 & 7 \\
$f(x,2)$ & 0 & 0 & 1 & 0 & 0 & 1 & 1 & 4 \\
$f(x,4)$ & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
$\texttt{ancestor}(x,1)$ & 0 & 1 & 4 & 1 & 1 & 2 & 4 & 7 \\
$\texttt{ancestor}(x,2)$ & 0 & 0 & 1 & 0 & 0 & 1 & 1 & 4 \\
$\texttt{ancestor}(x,4)$ & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\
$\cdots$ \\
\end{tabular}
\end{center}
The preprocessing takes $O(n \log n)$ time,
because $O(\log n)$ values are calculated for each node.
After this, any value of $f(x,k)$ can be calculated
After this, any value of $\texttt{ancestor}(x,k)$ can be calculated
in $O(\log k)$ time by representing $k$
as a sum where each term is a power of two.
@ -391,7 +390,7 @@ Using a tree traversal array, we can also efficiently
calculate sums of values on
paths from the root node to any
node of the tree.
Let us consider a problem where our task
Consider a problem where our task
is to support the following queries:
\begin{itemize}
\item change the value of a node
@ -436,7 +435,7 @@ $4+5+5=14$:
\end{tikzpicture}
\end{center}
We can solve this problem in a similar way as before,
We can solve this problem like before,
but now each value in the last row of the array is the sum of values
on a path from the root to the node.
For example, the following array corresponds to the above tree:
@ -477,17 +476,6 @@ For example, the following array corresponds to the above tree:
\node at (6.5,-1.5) {$12$};
\node at (7.5,-1.5) {$10$};
\node at (8.5,-1.5) {$6$};
%
% \footnotesize
% \node at (0.5,1.4) {$1$};
% \node at (1.5,1.4) {$2$};
% \node at (2.5,1.4) {$3$};
% \node at (3.5,1.4) {$4$};
% \node at (4.5,1.4) {$5$};
% \node at (5.5,1.4) {$6$};
% \node at (6.5,1.4) {$7$};
% \node at (7.5,1.4) {$8$};
% \node at (8.5,1.4) {$9$};
\end{tikzpicture}
\end{center}
@ -534,17 +522,6 @@ the array changes as follows:
\node at (6.5,-1.5) {$13$};
\node at (7.5,-1.5) {$11$};
\node at (8.5,-1.5) {$6$};
%
% \footnotesize
% \node at (0.5,1.4) {$1$};
% \node at (1.5,1.4) {$2$};
% \node at (2.5,1.4) {$3$};
% \node at (3.5,1.4) {$4$};
% \node at (4.5,1.4) {$5$};
% \node at (5.5,1.4) {$6$};
% \node at (6.5,1.4) {$7$};
% \node at (7.5,1.4) {$8$};
% \node at (8.5,1.4) {$9$};
\end{tikzpicture}
\end{center}
@ -608,7 +585,7 @@ two nodes whose lowest common ancestor we should find.
First, we move one of the pointers upwards
so that both pointers point to nodes at the same level.
In the example case, we move the second pointer one
In the example scenario, we move the second pointer one
level up so that it points to node 6
which is at the same level with node 5:
@ -640,7 +617,7 @@ they will point to the same node.
The node to which the pointers point after this
is the lowest common ancestor.
In the example case, it suffices to move both pointers
In the example scenario, it suffices to move both pointers
one step upwards to node 2,
which is the lowest common ancestor:
@ -726,7 +703,7 @@ in the array and there are a total of $2n-1$
nodes in the array.
We store two values in the array:
the identifier of the node and the level of the
the identifier of the node and the depth of the
node in the tree.
The following array corresponds to the above tree:
@ -734,10 +711,9 @@ The following array corresponds to the above tree:
\begin{tikzpicture}[scale=0.7]
\node[left] at (-1,1.5) {node id};
\node[left] at (-1,0.5) {level};
\node[left] at (-1,0.5) {depth};
\draw (0,1) grid (15,2);
%\node at (-1.1,1.5) {\texttt{node}};
\node at (0.5,1.5) {$1$};
\node at (1.5,1.5) {$2$};
\node at (2.5,1.5) {$5$};
@ -754,9 +730,7 @@ The following array corresponds to the above tree:
\node at (13.5,1.5) {$4$};
\node at (14.5,1.5) {$1$};
\draw (0,0) grid (15,1);
%\node at (-1.1,0.5) {\texttt{depth}};
\node at (0.5,0.5) {$1$};
\node at (1.5,0.5) {$2$};
\node at (2.5,0.5) {$3$};
@ -793,7 +767,7 @@ The following array corresponds to the above tree:
\end{center}
Now we can find the lowest common ancestor
of nodes $a$ and $b$ by finding the node with the \emph{lowest} level
of nodes $a$ and $b$ by finding the node with the \emph{minimum} depth
between nodes $a$ and $b$ in the array.
For example, the lowest common ancestor of nodes $5$ and $8$
can be found as follows:
@ -802,7 +776,7 @@ can be found as follows:
\begin{tikzpicture}[scale=0.7]
\node[left] at (-1,1.5) {node id};
\node[left] at (-1,0.5) {level};
\node[left] at (-1,0.5) {depth};
\fill[color=lightgray] (2,1) rectangle (3,2);
\fill[color=lightgray] (5,1) rectangle (6,2);
@ -865,9 +839,9 @@ can be found as follows:
\end{center}
Node 5 is at position 2, node 8 is at position 5,
and the node with lowest level between
and the node with minimum depth between
positions $2 \ldots 5$ is node 2 at position 3
whose level is 2.
whose depth is 2.
Thus, the lowest common ancestor of
nodes 5 and 8 is node 2.
@ -880,22 +854,19 @@ after an $O(n \log n)$ time preprocessing.
\subsubsection{Distances of nodes}
Finally, let us consider the problem of
calculating the distance between
two nodes of a tree, which equals
the length of the path between them.
It turns out that this problem reduces to
finding the lowest common ancestor of the nodes.
The distance between nodes $a$ and $b$
equals the length of the path from $a$ to $b$.
It turns out that the problem of calculating
the distance between nodes reduces to
finding their lowest common ancestor.
First, we root the tree arbitrarily.
After this, the distance between nodes $a$ and $b$
After this, the distance of nodes $a$ and $b$
can be calculated using the formula
\[d(a)+d(b)-2 \cdot d(c),\]
\[\texttt{depth}(a)+\texttt{depth}(b)-2 \cdot \texttt{depth}(c),\]
where $c$ is the lowest common ancestor of $a$ and $b$
and $d(s)$ denotes the distance from the root
to node $s$.
For example, in the tree
and $\texttt{depth}(s)$ denotes the depth of node $s$.
For example, consider the distance of nodes 5 and 8:
\begin{center}
\begin{tikzpicture}[scale=0.9]
\node[draw, circle] (1) at (0,3) {$1$};
@ -919,12 +890,10 @@ For example, in the tree
\path[draw=red,thick,-,line width=2pt] (6) -- node[font=\small] {} (3);
\end{tikzpicture}
\end{center}
the lowest common ancestor of nodes 5 and 8 is node 2.
A path from node 5 to node 8
first ascends from node 5 to node 2
and then descends from node 2 to node 8.
The distances of the nodes from the root are
$d(5)=3$, $d(8)=4$ and $d(2)=2$,
The lowest common ancestor of nodes 5 and 8 is node 2.
The depths of the nodes are
$\texttt{depth}(5)=3$, $\texttt{depth}(8)=4$ and $\texttt{depth}(2)=2$,
so the distance between nodes 5 and 8 is
$3+4-2\cdot2=3$.
@ -1167,7 +1136,7 @@ is the highest node in the set of $y$.
Then, after processing node $x$,
the algorithm joins the sets of $x$ and its parent.
For example, assume that we wish to find the lowest
For example, suppose that we want to find the lowest
common ancestors of node pairs $(5,8)$
and $(2,7)$ in the following tree:
\begin{center}
@ -1190,7 +1159,7 @@ and $(2,7)$ in the following tree:
\end{tikzpicture}
\end{center}
In the following pictures, gray nodes denote visited nodes
In the following trees, gray nodes denote visited nodes
and dashed groups of nodes belong to the same set.
When the algorithm visits node 8, it notices that
node 5 has been visited and the highest node