Corrections

This commit is contained in:
Antti H S Laaksonen 2017-02-04 01:54:48 +02:00
parent 660e6f6e14
commit 1319f46f0e
1 changed files with 74 additions and 69 deletions

View File

@ -5,16 +5,15 @@
\index{minimum query} \index{minimum query}
\index{maximum query} \index{maximum query}
In a \key{range query}, a range of an array A \key{range query} asks to calculate some information
is given and we should calculate some value from the about the elements in a given range of an array.
elements in the range. Typical range queries are: Typical range queries are:
\begin{itemize} \begin{itemize}
\item \key{sum query}: calculate the sum of elements in range $[a,b]$ \item \key{sum query}: calculate the sum of elements in a range
\item \key{minimum query}: find the smallest element in range $[a,b]$ \item \key{minimum query}: find the smallest element in a range
\item \key{maximum query}: find the largest element in range $[a,b]$ \item \key{maximum query}: find the largest element in a range
\end{itemize} \end{itemize}
For example, in range $[4,7]$ of the following array, For example, consider the range $[4,7]$ in the following array:
the sum is $4+6+1+3=14$, the minimum is 1 and the maximum is 6:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\fill[color=lightgray] (3,0) rectangle (7,1); \fill[color=lightgray] (3,0) rectangle (7,1);
@ -40,10 +39,14 @@ the sum is $4+6+1+3=14$, the minimum is 1 and the maximum is 6:
\node at (7.5,1.4) {$8$}; \node at (7.5,1.4) {$8$};
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
In this range, the sum of elements is $4+6+1+3=16$,
the minimum element is 1 and the maximum element is 6.
An easy way to answer a range query is
to iterate through all the elements in the range. An easy way to process range queries is
For example, we can answer a sum query as follows: to go through all the elements in the range.
For example, we can calculate the sum
in a range $[a,b]$ as follows:
\begin{lstlisting} \begin{lstlisting}
int sum(int a, int b) { int sum(int a, int b) {
@ -55,34 +58,34 @@ int sum(int a, int b) {
} }
\end{lstlisting} \end{lstlisting}
The above function handles a sum query The above function works in $O(n)$ time.
in $O(n)$ time, which is slow if the array is large However, if the array is large and there are several queries,
and there are a lot of queries. such an approach is slow.
In this chapter we will learn how In this chapter, we will learn how
range queries can be answered much more efficiently. range queries can be processed much more efficiently.
\section{Static array queries} \section{Static array queries}
We will first focus on a simple case where We first focus on a simple situation where
the array is \key{static}, i.e., the array is \key{static}, i.e.,
the elements never change between the queries. the elements never change between the queries.
In this case, it suffices to process the In this case, it suffices to preprocess the
contents of the array beforehand and construct array and construct
a data structure that can be used for answering a data structure that can be used for
finding the answer for
any possible range query efficiently. any possible range query efficiently.
\subsubsection{Sum query} \subsubsection{Sum query}
\index{prefix sum array} \index{prefix sum array}
Sum queries can be answered efficiently Sum queries can be processed efficiently
by constructing a \key{sum array} by constructing a \key{sum array}
that contains the sum of the range $[1,k]$ that contains the sum of elements in the range $[1,k]$
for each $k=1,2,\ldots,n$. for each $k=1,2,\ldots,n$.
After this, the sum of any range $[a,b]$ of the Using the sum array, the sum of elements in
original array any range $[a,b]$ of the original array can
can be calculated in $O(1)$ time using the be calculated in $O(1)$ time.
precalculated sum array.
For example, for the array For example, for the array
\begin{center} \begin{center}
@ -137,27 +140,27 @@ the corresponding sum array is as follows:
\node at (7.5,1.4) {$8$}; \node at (7.5,1.4) {$8$};
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
The following code constructs a prefix sum The following code constructs a sum array
array \texttt{s} from array \texttt{t} in $O(n)$ time: \texttt{s} for an array \texttt{t} in $O(n)$ time:
\begin{lstlisting} \begin{lstlisting}
for (int i = 1; i <= n; i++) { for (int i = 1; i <= n; i++) {
s[i] = s[i-1]+t[i]; s[i] = s[i-1]+t[i];
} }
\end{lstlisting} \end{lstlisting}
After this, the following function answers After this, the following function processes
a sum query in $O(1)$ time: any sum query in $O(1)$ time:
\begin{lstlisting} \begin{lstlisting}
int sum(int a, int b) { int sum(int a, int b) {
return s[b]-s[a-1]; return s[b]-s[a-1];
} }
\end{lstlisting} \end{lstlisting}
The function calculates the sum of range $[a,b]$ The function calculates the sum in the range $[a,b]$
by subtracting the sum of range $[1,a-1]$ by subtracting the sum in the range $[1,a-1]$
from the sum of range $[1,b]$. from the sum in the range $[1,b]$.
Thus, only two values from the sum array Thus, only two values of the sum array
are needed, and the query takes $O(1)$ time. are needed, and the query takes $O(1)$ time.
Note that thanks to the one-based indexing, Note that because of the one-based indexing,
the function also works when $a=1$ if $\texttt{s}[0]=0$. the function also works when $a=1$ if $\texttt{s}[0]=0$.
As an example, consider the range $[4,7]$: As an example, consider the range $[4,7]$:
@ -186,9 +189,9 @@ As an example, consider the range $[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 the range $[4,7]$ is $8+6+1+4=19$. The sum in the range is $8+6+1+4=19$.
This can be calculated from the sum array This can be calculated using the precalculated
using the sums $[1,3]$ and $[1,7]$: sums for the ranges $[1,3]$ and $[1,7]$:
\begin{center} \begin{center}
\begin{tikzpicture}[scale=0.7] \begin{tikzpicture}[scale=0.7]
\fill[color=lightgray] (2,0) rectangle (3,1); \fill[color=lightgray] (2,0) rectangle (3,1);
@ -216,14 +219,15 @@ using the sums $[1,3]$ and $[1,7]$:
\node at (7.5,1.4) {$8$}; \node at (7.5,1.4) {$8$};
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
Thus, the sum of the range $[4,7]$ is $27-8=19$. Thus, the sum in the range $[4,7]$ is $27-8=19$.
We can also generalize the idea of a sum array It is also possible to generalize this idea
for a two-dimensional array. to higher dimensions.
In this case, it will be possible to calculate the sum of For example, we can construct a two-dimensional
any rectangular subarray in $O(1)$ time. sum array that can be used for calculating
The sum array will contain sums the sum of any rectangular subarray in $O(1)$ time.
for all subarrays that begin from the upper-left corner. Each value in such an array is the sum of a subarray
that begins at the upper-left corner of the array.
\begin{samepage} \begin{samepage}
The following picture illustrates the idea: The following picture illustrates the idea:
@ -240,23 +244,23 @@ The following picture illustrates the idea:
\end{center} \end{center}
\end{samepage} \end{samepage}
The sum inside the gray subarray can be calculated The sum of the gray subarray can be calculated
using the formula using the formula
\[S(A) - S(B) - S(C) + S(D)\] \[S(A) - S(B) - S(C) + S(D),\]
where $S(X)$ denotes the sum in a rectangular where $S(X)$ denotes the sum of a rectangular
subarray from the upper-left corner subarray from the upper-left corner
to the position of letter $X$. to the position of $X$.
\subsubsection{Minimum query} \subsubsection{Minimum query}
It is also possible to answer a minimum query It is also possible to process minimum queries
in $O(1)$ time after preprocessing, though it is in $O(1)$ time after preprocessing, though it is
more difficult than answer a sum query. more difficult than processing sum queries.
Note that minimum and maximum queries can always Note that minimum and maximum queries can always
be implemented using same techniques, be implemented using same techniques,
so it suffices to focus on the minimum query. so it suffices to focus on minimum queries.
The idea is to find the minimum element for each range The idea is to precalculate the minimum element of each range
of size $2^k$ in the array. of size $2^k$ in the array.
For example, in the array For example, in the array
@ -336,21 +340,22 @@ $[1,8]$ & 8 & 1 \\
\end{center} \end{center}
The number of $2^k$ ranges in an array is $O(n \log n)$ There are $O(n \log n)$ ranges of size $2^k$,
because there are $O(\log n)$ ranges that begin because for each array position,
from each array index. there are $O(\log n)$ ranges that begin at that position.
The minima for all $2^k$ ranges can be calculated The minima in all ranges of size $2^k$ can be calculated
in $O(n \log n)$ time because each $2^k$ range in $O(n \log n)$ time, because each range of size $2^k$
consists of two $2^{k-1}$ ranges, so the minima consists of two ranges of size $2^{k-1}$ and the minima
can be calculated recursively. can be calculated recursively.
After this, the minimum of any range $[a,b]$c After this, the minimum in any range $[a,b]$
can be calculated in $O(1)$ time as a minimum of can be calculated in $O(1)$ time as a minimum of
two $2^k$ ranges where $k=\lfloor \log_2(b-a+1) \rfloor$. two ranges of size $2^k$ where $k=\lfloor \log_2(b-a+1) \rfloor$.
The first range begins from index $a$, The first range begins at index $a$,
and the second range ends to index $b$. and the second range ends at index $b$.
The parameter $k$ is so chosen that The parameter $k$ is chosen so that
two $2^k$ ranges cover the range $[a,b]$ entirely. the two ranges of size $2^k$
fully cover the range $[a,b]$.
As an example, consider the range $[2,7]$: As an example, consider the range $[2,7]$:
\begin{center} \begin{center}
@ -378,7 +383,7 @@ As an example, consider the range $[2,7]$:
\node at (7.5,1.4) {$8$}; \node at (7.5,1.4) {$8$};
\end{tikzpicture} \end{tikzpicture}
\end{center} \end{center}
The length of the range $[2,7]$ is 6, The length of the range is 6,
and $\lfloor \log_2(6) \rfloor = 2$. and $\lfloor \log_2(6) \rfloor = 2$.
Thus, the minimum can be calculated Thus, the minimum can be calculated
from two ranges of length 4. from two ranges of length 4.
@ -434,9 +439,9 @@ The ranges are $[2,5]$ and $[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 minimum of the range $[2,5]$ is 3, Since the minimum in the range $[2,5]$ is 3
and the minimum of the range $[4,7]$ is 1. and the minimum in the range $[4,7]$ is 1,
Thus, the minimum of the range $[2,7]$ is 1. we know that the minimum in the range $[2,7]$ is 1.
\section{Binary indexed tree} \section{Binary indexed tree}