Corrections
This commit is contained in:
parent
660e6f6e14
commit
1319f46f0e
143
luku09.tex
143
luku09.tex
|
@ -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}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue