Corrections

This commit is contained in:
Antti H S Laaksonen 2017-02-04 14:04:02 +02:00
parent d71d3957fb
commit b2931ed5da
1 changed files with 133 additions and 135 deletions

View File

@ -687,8 +687,8 @@ and when updating the array,
the position $k$ should be increased by $k \& -k$ at every step. the position $k$ should be increased by $k \& -k$ at every step.
Suppose that the binary indexed tree is stored in an array \texttt{b}. Suppose that the binary indexed tree is stored in an array \texttt{b}.
The following function \texttt{sum} calculates The following function calculates
the sum of elements in the range $[1,k]$: the sum of elements in a range $[1,k]$:
\begin{lstlisting} \begin{lstlisting}
int sum(int k) { int sum(int k) {
int s = 0; int s = 0;
@ -700,7 +700,7 @@ int sum(int k) {
} }
\end{lstlisting} \end{lstlisting}
The following function \texttt{add} increases the value The following function increases the value
of the element at position $k$ by $x$ of the element at position $k$ by $x$
($x$ can be positive or negative): ($x$ can be positive or negative):
\begin{lstlisting} \begin{lstlisting}
@ -723,11 +723,11 @@ takes $O(1)$ time using bit operations.
\index{segment tree} \index{segment tree}
A \key{segment tree} is a data structure A \key{segment tree} is a data structure
whose supported operations are that supports two operations:
handling a range query for range $[a,b]$ processing a range query and
and updating the element at index $k$. modifying an element in the array.
Using a segment tree, we can implement sum Segment trees can support
queries, minimum queries and many other sum queries, minimum and maximum queries and many other
queries so that both operations work in $O(\log n)$ time. queries so that both operations work in $O(\log n)$ time.
Compared to a binary indexed tree, Compared to a binary indexed tree,
@ -740,16 +740,15 @@ memory and is a bit more difficult to implement.
\subsubsection{Structure} \subsubsection{Structure}
A segment tree contains $2n-1$ nodes A segment tree is a binary tree that
so that the bottom $n$ nodes correspond contains $2n-1$ nodes.
to the original array and the other nodes The nodes on the bottom level of the tree
contain information needed for range queries. correspond to the original array,
The values in a segment tree depend on and the other nodes
the supported query type. contain information needed for processing range queries.
We will first assume that the supported
query is the sum query.
For example, the array We will first discuss segment trees that support
sum queries. As an example, consider the following array:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\draw (0,0) grid (8,1); \draw (0,0) grid (8,1);
@ -763,18 +762,18 @@ For example, the array
\node at (6.5,0.5) {$2$}; \node at (6.5,0.5) {$2$};
\node at (7.5,0.5) {$6$}; \node at (7.5,0.5) {$6$};
\footnotesize % \footnotesize
\node at (0.5,1.4) {$1$}; % \node at (0.5,1.4) {$1$};
\node at (1.5,1.4) {$2$}; % \node at (1.5,1.4) {$2$};
\node at (2.5,1.4) {$3$}; % \node at (2.5,1.4) {$3$};
\node at (3.5,1.4) {$4$}; % \node at (3.5,1.4) {$4$};
\node at (4.5,1.4) {$5$}; % \node at (4.5,1.4) {$5$};
\node at (5.5,1.4) {$6$}; % \node at (5.5,1.4) {$6$};
\node at (6.5,1.4) {$7$}; % \node at (6.5,1.4) {$7$};
\node at (7.5,1.4) {$8$}; % \node at (7.5,1.4) {$8$};
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
corresponds to the following segment tree: The corresponding segment tree is as follows:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\draw (0,0) grid (8,1); \draw (0,0) grid (8,1);
@ -823,22 +822,18 @@ and it can be calculated as the sum of
the values of its left and right child node. the values of its left and right child node.
It is convenient to build a segment tree It is convenient to build a segment tree
when the size of the array is a power of two for an array whose size is a power of two,
and the tree is a complete binary tree. because in this case every internal node has a left
and right child.
In the sequel, we will assume that the tree In the sequel, we will assume that the tree
is built like this. is built like this.
If the size of the array is not a power of two, If the size of the array is not a power of two,
we can always extend it using zero elements. we can always add zero elements to the array.
\subsubsection{Range query} \subsubsection{Range query}
In a segment tree, the answer for a range query The sum of elements in a given range
is calculated from nodes that belong to the range can be calculated as a sum of values in the segment tree.
and are as high as possible in the tree.
Each node gives the answer for a subrange,
and the answer for the entire range can be
calculated by combining these values.
For example, consider the following range: For example, consider the following range:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
@ -853,22 +848,22 @@ For example, consider the following range:
\node[anchor=center] at (5.5, 0.5) {7}; \node[anchor=center] at (5.5, 0.5) {7};
\node[anchor=center] at (6.5, 0.5) {2}; \node[anchor=center] at (6.5, 0.5) {2};
\node[anchor=center] at (7.5, 0.5) {6}; \node[anchor=center] at (7.5, 0.5) {6};
%
\footnotesize % \footnotesize
\node at (0.5,1.4) {$1$}; % \node at (0.5,1.4) {$1$};
\node at (1.5,1.4) {$2$}; % \node at (1.5,1.4) {$2$};
\node at (2.5,1.4) {$3$}; % \node at (2.5,1.4) {$3$};
\node at (3.5,1.4) {$4$}; % \node at (3.5,1.4) {$4$};
\node at (4.5,1.4) {$5$}; % \node at (4.5,1.4) {$5$};
\node at (5.5,1.4) {$6$}; % \node at (5.5,1.4) {$6$};
\node at (6.5,1.4) {$7$}; % \node at (6.5,1.4) {$7$};
\node at (7.5,1.4) {$8$}; % \node at (7.5,1.4) {$8$};
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
The sum of elements in the range $[3,8]$ is The sum of elements in the range is
$6+3+2+7+2+6=26$. $6+3+2+7+2+6=26$.
The sum can be calculated from the segment tree The following two nodes in the tree
using the following subranges: cover the range:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\draw (0,0) grid (8,1); \draw (0,0) grid (8,1);
@ -907,22 +902,23 @@ using the following subranges:
\path[draw,thick,-] (m) -- (j); \path[draw,thick,-] (m) -- (j);
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Thus, the sum of the range is $9+17=26$. Thus, the sum of elements in the range is $9+17=26$.
When the answer for a range query is When the sum is calculated using nodes
calculated using as high nodes as possible, that are located as high as possible in the tree,
at most two nodes on each level at most two nodes on each level
of the segment tree are needed. of the tree are needed.
Because of this, the total number of nodes Hence, the total number of nodes
examined is only $O(\log n)$. examined is only $O(\log n)$.
\subsubsection{Array update} \subsubsection{Array update}
When an element in the array changes, When an element in the array changes,
we should update all nodes in the segment tree we should update all nodes in the tree
whose value depends on the changed element. whose value depends on the element.
This can be done by travelling from the bottom This can be done by traversing the path
to the top in the tree and updating the nodes along the path. from the element to the top node
and updating the nodes along the path.
\begin{samepage} \begin{samepage}
The following picture shows which nodes in the segment tree The following picture shows which nodes in the segment tree
@ -969,24 +965,24 @@ change if the element 7 in the array changes.
\end{center} \end{center}
\end{samepage} \end{samepage}
The path from the bottom of the segment tree to the top The path from bottom to top
always consists of $O(\log n)$ nodes, always consists of $O(\log n)$ nodes,
so updating the array affects $O(\log n)$ nodes in the tree. so each update changes $O(\log n)$ nodes in the tree.
\subsubsection{Storing the tree} \subsubsection{Storing the tree}
A segment tree can be stored as an array A segment tree can be stored in an array
of $2N$ elements where $N$ is a power of two. of $2N$ elements where $N$ is a power of two.
From now on, we will assume that the indices From now on, we will assume that the indices
of the original array are between $0$ and $N-1$. of the original array are between $0$ and $N-1$.
The element at index 1 in the segment tree array The element at position 1 in the array
contains the top node of the tree, corresponds to the top node of the tree,
the elements at indices 2 and 3 correspond to the elements at positions 2 and 3 correspond to
the second level of the tree, and so on. the second level of the tree, and so on.
Finally, the elements beginning from index $N$ Finally, the elements at positions $N \ldots 2N-1$
contain the bottom level of the tree, i.e., correspond to the bottom level of the tree, i.e.,
the actual content of the original array. the elements of the original array.
For example, the segment tree For example, the segment tree
\begin{center} \begin{center}
@ -1068,11 +1064,11 @@ can be stored as follows ($N=8$):
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Using this representation, Using this representation,
for a node at index $k$, for a node at position $k$,
\begin{itemize} \begin{itemize}
\item the parent node is at index $\lfloor k/2 \rfloor$, \item the parent node is at position $\lfloor k/2 \rfloor$,
\item the left child node is at index $2k$, and \item the left child node is at position $2k$, and
\item the right child node is at index $2k+1$. \item the right child node is at position $2k+1$.
\end{itemize} \end{itemize}
Note that this implies that the index of a node Note that this implies that the index of a node
is even if it is a left child and odd if it is a right child. is even if it is a left child and odd if it is a right child.
@ -1080,8 +1076,9 @@ is even if it is a left child and odd if it is a right child.
\subsubsection{Functions} \subsubsection{Functions}
We assume that the segment tree is stored We assume that the segment tree is stored
in the array \texttt{p}. in an array \texttt{p}.
The following function calculates the sum of range $[a,b]$: The following function
calculates the sum of elements in a range $[a,b]$:
\begin{lstlisting} \begin{lstlisting}
int sum(int a, int b) { int sum(int a, int b) {
@ -1096,15 +1093,18 @@ int sum(int a, int b) {
} }
\end{lstlisting} \end{lstlisting}
The function begins from the bottom of the tree The function maintains a range in the segment tree array.
and moves step by step upwards in the tree. Initially the range is $[a+N,b+N]$,
The function calculates the range sum to that corresponds to the range $[a,b]$
the variable $s$ by combining the sums in the tree nodes. in the underlying array.
The value of a node is added to the sum if At each step, the function adds the value of
the parent node doesn't belong to the range. the left and right node to the sum
if their parent nodes do not belong to the range.
After this, the same process continues on the
next level of the tree.
The function \texttt{add} increases the value The following function increases the value
of element $k$ by $x$: of the element at position $k$ by $x$:
\begin{lstlisting} \begin{lstlisting}
void add(int k, int x) { void add(int k, int x) {
@ -1115,28 +1115,27 @@ void add(int k, int x) {
} }
} }
\end{lstlisting} \end{lstlisting}
First the function updates the bottom level First the function updates the element
of the tree that corresponds to the original array. at the bottom level of the tree.
After this, the function updates the values of all After this, the function updates the values of all
internal nodes in the tree, until it reaches internal nodes in the tree, until it reaches
the root node of the tree. the top node of the tree.
Both operations in the segment tree work Both above functions work
in $O(\log n)$ time because a segment tree in $O(\log n)$ time, because a segment tree
of $n$ elements consists of $O(\log n)$ levels, of $n$ elements consists of $O(\log n)$ levels,
and the operations move one level forward at each step. and the operations move one level forward in the tree at each step.
\subsubsection{Other queries} \subsubsection{Other queries}
Besides the sum query, A segment tree can support any query
the segment tree can support any range query where the answer for a range $[a,b]$
where the answer for range $[a,b]$ can be calculated
can be efficiently calculated from the answers for ranges $[a,c]$ and $[c+1,b]$, where
from ranges $[a,c]$ and $[c+1,b]$ where $c$ is some index between $a$ and $b$.
$c$ is some element between $a$ and $b$. Examples of such queries are
Such queries are, for example,
minimum and maximum, greatest common divisor, minimum and maximum, greatest common divisor,
and bit operations. and bit operations and, or and xor.
\begin{samepage} \begin{samepage}
For example, the following segment tree For example, the following segment tree
@ -1184,23 +1183,23 @@ supports minimum queries:
In this segment tree, every node in the tree In this segment tree, every node in the tree
contains the smallest element in the corresponding contains the smallest element in the corresponding
range of the original array. range of the underlying array.
The top node of the tree contains the smallest The top node of the tree contains the smallest
element in the array. element in the whole array.
The tree can be implemented like previously, The operations can be implemented like previously,
but instead of sums, minima are calculated. but instead of sums, minima are calculated.
\subsubsection{Binary search in tree} \subsubsection{Binary search in tree}
The structure of the segment tree makes it possible The structure of the segment tree allows us
to use binary search. to use binary search for finding elements in the array.
For example, if the tree supports the minimum query, For example, if the tree supports the minimum query,
we can find the index of the smallest we can find the position of the smallest
element in $O(\log n)$ time. element in $O(\log n)$ time.
For example, in the following tree the For example, in the following tree the
smallest element is 1 that can be found smallest element 1 can be found
by following a path downwards from the top node: by traversing a path downwards from the top node:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
@ -1252,31 +1251,31 @@ by following a path downwards from the top node:
\subsubsection{Index compression} \subsubsection{Index compression}
A limitation in data structures that have A limitation in data structures that
been built upon an array is that are built upon an array is that
the elements are indexed using integers the elements are indexed using integers
$1,2,3,$ etc. $1,2,3,$ etc.
Difficulties arise when the indices Difficulties arise when large indices
needed are large. are needed.
For example, using the index $10^9$ would For example, if we wish to use the index $10^9$,
require that the array would contain $10^9$ the array should contain $10^9$
elements which is not realistic. elements which is not realistic.
\index{index compression} \index{index compression}
However, we can often bypass this limitation However, we can often bypass this limitation
by using \key{index compression} by using \key{index compression},
where the indices are redistributed so that where the original indices are replaced
they are integers $1,2,3,$ etc. with the indices $1,2,3,$ etc.
This can be done if we know all the indices This can be done if we know all the indices
needed during the algorithm beforehand. needed during the algorithm beforehand.
The idea is to replace each original index $x$ The idea is to replace each original index $x$
with index $p(x)$ where $p$ is a function that with $p(x)$ where $p$ is a function that
redistributes the indices. compresses the indices.
We require that the order of the indices We require that the order of the indices
doesn't change, so if $a<b$, then $p(a)<p(b)$. does not change, so if $a<b$, then $p(a)<p(b)$.
Thanks to this, we can conviently perform queries This allows us to conviently perform queries
despite the fact that the indices are compressed. despite the fact that the indices are compressed.
For example, if the original indices are For example, if the original indices are
@ -1295,15 +1294,15 @@ p(10^9) & = & 3 \\
So far, we have implemented data structures So far, we have implemented data structures
that support range queries and modifications that support range queries and modifications
of single values. of single values.
Let us now consider a reverse situation Let us now consider a reverse situation,
where we should update ranges and where we should update ranges and
retrieve single values. retrieve single values.
We focus on an operation that increases all We focus on an operation that increases all
elements in range $[a,b]$ by $x$. elements in a range $[a,b]$ by $x$.
Surprisingly, we can use the data structures Surprisingly, we can use the data structures
presented in this chapter also in this situation. presented in this chapter also in this situation.
This requires that we change the array so that To do this, we change the array so that
each element indicates the \emph{change} each element indicates the \emph{change}
with respect to the previous element. with respect to the previous element.
For example, the array For example, the array
@ -1361,18 +1360,18 @@ becomes as follows:
\end{center} \end{center}
The original array is the sum array of the new array. The original array is the sum array of the new array.
Thus, any value in the original array corresponds Thus, each element in the original array equals
to a sum of elements in the new array. a sum of values in the new array.
For example, the value 6 at index 5 in the original array For example, the value 5 at position 6 in the original array
corresponds to the sum $3-2+4=5$. corresponds to the sum $3-2+4=5$.
The benefit in using the new array is The benefit in using the new array is
that we can update a range by changing just that we can update a range by changing just
two elements in the new array. two elements in the array.
For example, if we want to For example, if we want to
increase the range $2 \ldots 5$ by 5, increase the elements in the range $2 \ldots 5$ by 5,
it suffices to increase the element at index 2 by 5 it suffices to increase the value at position 2 by 5
and decrease the element at index 6 by 5. and decrease the value at position 6 by 5.
The result is as follows: The result is as follows:
\begin{center} \begin{center}
@ -1400,18 +1399,17 @@ The result is as follows:
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
More generally, to increase the range More generally, to increase the elements
$a \ldots b$ by $x$, in the range $[a,b]$ by $x$,
we increase the element at index $a$ by $x$ we increase the value at position $a$ by $x$
and decrease the element at index $b+1$ by $x$. and decrease the value at position $b+1$ by $x$.
The required operations are calculating Thus, it is only needed to update single values
the sum in a range and updating a value, and process sum queries,
so we can use a binary indexed tree or a segment tree. so we can use a binary indexed tree or a segment tree.
A more difficult problem is to support both A more difficult problem is to support both
range queries and range updates. range queries and range updates.
In Chapter 28 we will see that this is possible In Chapter 28 we will see that even this is possible.
as well.