Corrections
This commit is contained in:
parent
1319f46f0e
commit
d71d3957fb
113
luku09.tex
113
luku09.tex
|
@ -448,31 +448,33 @@ we know that the minimum in the range $[2,7]$ is 1.
|
||||||
\index{binary indexed tree}
|
\index{binary indexed tree}
|
||||||
\index{Fenwick tree}
|
\index{Fenwick tree}
|
||||||
|
|
||||||
A \key{binary indexed tree} or a \key{Fenwick tree}
|
A \key{binary indexed tree} or \key{Fenwick tree}
|
||||||
is a data structure that resembles a sum array.
|
can be seen as a dynamic version of a sum array.
|
||||||
The supported operations are answering
|
The tree supports two $O(\log n)$ time operations:
|
||||||
a sum query for range $[a,b]$,
|
calculating the sum of elements in a range,
|
||||||
and updating the element at index $k$.
|
and modifying the value of an element.
|
||||||
The time complexity for both of the operations is $O(\log n)$.
|
|
||||||
|
|
||||||
Unlike a sum array, a binary indexed tree
|
The benefit in using a binary indexed tree is
|
||||||
can be efficiently updated between the sum queries.
|
that the elements of the underlying array
|
||||||
This would not be possible using a sum array
|
can be efficiently updated between the queries.
|
||||||
because we should build the whole sum array again
|
This would not be possible with a sum array,
|
||||||
in $O(n)$ time after each update.
|
because after each update, we should build the
|
||||||
|
whole sum array again in $O(n)$ time.
|
||||||
|
|
||||||
\subsubsection{Structure}
|
\subsubsection{Structure}
|
||||||
|
|
||||||
A binary indexed tree can be represented as an array
|
Given an array of $n$ elements, indexed $1 \ldots n$,
|
||||||
where index $k$ contains the sum of a range in the
|
the binary indexed tree for that array
|
||||||
original array that ends to index $k$.
|
is an array such that the value at position $k$
|
||||||
|
equals the sum of elements in the original array in a range
|
||||||
|
that ends at position $k$.
|
||||||
The length of the range is the largest power of two
|
The length of the range is the largest power of two
|
||||||
that divides $k$.
|
that divides $k$.
|
||||||
For example, if $k=6$, the length of the range is $2$
|
For example, if $k=6$, the length of the range is $2$,
|
||||||
because $2$ divides $6$ but $4$ doesn't divide $6$.
|
because $2$ divides $6$ but $4$ does not divide $6$.
|
||||||
|
|
||||||
\begin{samepage}
|
\begin{samepage}
|
||||||
For example, for the array
|
For 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);
|
||||||
|
@ -498,7 +500,7 @@ For example, for the array
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
\end{samepage}
|
\end{samepage}
|
||||||
the corresponding binary indexed tree is as follows:
|
The corresponding binary indexed tree is as follows:
|
||||||
\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);
|
||||||
|
@ -543,21 +545,21 @@ the corresponding binary indexed tree is as follows:
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
For example, the binary indexed tree
|
For example, the value at position 6
|
||||||
contains the value 7 at index 6
|
in the binary indexed tree is 7,
|
||||||
because the sum of the elements in the range $[5,6]$
|
because the sum of elements in the range $[5,6]$
|
||||||
of the original array is $6+1=7$.
|
in the original array is $6+1=7$.
|
||||||
|
|
||||||
\subsubsection{Sum query}
|
\subsubsection{Sum query}
|
||||||
|
|
||||||
The basic operation in a binary indexed tree is
|
The basic operation in a binary indexed tree is
|
||||||
calculating the sum of a range $[1,k]$ where $k$
|
to calculate the sum of elements in a range $[1,k]$,
|
||||||
is any index in the array.
|
where $k$ is any position in the array.
|
||||||
The sum of any range can be constructed by combining
|
The sum of such a range can be calculated as a
|
||||||
sums of subranges in the tree.
|
sum of one or more values stored in the tree.
|
||||||
|
|
||||||
For example, the range $[1,7]$ will be divided
|
For example, the range $[1,7]$ corresponds to
|
||||||
into three subranges:
|
the following values:
|
||||||
\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);
|
||||||
|
@ -602,25 +604,24 @@ into three subranges:
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
Thus, the sum of the range $[1,7]$ is $16+7+4=27$.
|
Hence, the sum of elements in the range $[1,7]$ is $16+7+4=27$.
|
||||||
Because of the structure of the binary indexed tree,
|
The structure of the binary indexed tree allows us to calculate
|
||||||
the length of each subrange inside a range is distinct,
|
the sum of elements in any range using only $O(\log n)$
|
||||||
so the sum of a range
|
values from the tree.
|
||||||
always consists of sums of $O(\log n)$ subranges.
|
|
||||||
|
|
||||||
Using the same technique that we previously used
|
Using the same technique that we previously used
|
||||||
with a sum array,
|
with a sum array,
|
||||||
we can efficiently calculate the sum of any range
|
we can efficiently calculate the sum of any range
|
||||||
$[a,b]$ by substracting the sum of the range $[1,a-1]$
|
$[a,b]$ by substracting the sum of the range $[1,a-1]$
|
||||||
from the sum of the range $[1,b]$.
|
from the sum of the range $[1,b]$.
|
||||||
The time complexity remains $O(\log n)$
|
Also here, only $O(\log n)$ values are needed,
|
||||||
because it suffices to calculate two sums of $[1,k]$ ranges.
|
because it suffices to calculate two sums of $[1,k]$ ranges.
|
||||||
|
|
||||||
\subsubsection{Array update}
|
\subsubsection{Array update}
|
||||||
|
|
||||||
When an element in the original array changes,
|
When an element in the original array changes,
|
||||||
several sums in the binary indexed tree change.
|
several sums in the binary indexed tree change.
|
||||||
For example, if the value at index 3 changes,
|
For example, if the element at position 3 changes,
|
||||||
the sums of the following ranges change:
|
the sums of the following ranges change:
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tikzpicture}[scale=0.7]
|
\begin{tikzpicture}[scale=0.7]
|
||||||
|
@ -666,28 +667,28 @@ the sums of the following ranges change:
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
Also in this case, the length of each range is distinct,
|
However, it turns out that
|
||||||
so $O(\log n)$ ranges will be updated in the binary indexed tree.
|
the number of values that need to be updated
|
||||||
|
in the binary indexed tree is only $O(\log n)$.
|
||||||
|
|
||||||
\subsubsection{Implementation}
|
\subsubsection{Implementation}
|
||||||
|
|
||||||
The operations of a binary indexed tree can be implemented
|
The operations of a binary indexed tree can be implemented
|
||||||
in an elegant and efficient way using bit manipulation.
|
in an elegant and efficient way using bit operations.
|
||||||
The bit operation needed is $k \& -k$ that
|
The key fact needed is that $k \& -k$
|
||||||
returns the last bit one from number $k$.
|
isolates the last one bit in a number $k$.
|
||||||
For example, $6 \& -6=2$ because the number $6$
|
For example, $6 \& -6=2$ because the number $6$
|
||||||
corresponds to 110 and the number $2$ corresponds to 10.
|
corresponds to 110 and the number $2$ corresponds to 10.
|
||||||
|
|
||||||
It turns out that when calculating a range sum,
|
It turns out that when processing a range query,
|
||||||
the index $k$ in the binary indexed tree should be
|
the position $k$ in the binary indexed tree should be
|
||||||
decreased by $k \& -k$ at every step.
|
decreased by $k \& -k$ at every step,
|
||||||
Correspondingly, when updating the array,
|
and when updating the array,
|
||||||
the index $k$ should be increased by $k \& -k$ at every step.
|
the position $k$ should be increased by $k \& -k$ at every step.
|
||||||
|
|
||||||
The following functions assume that the binary indexed tree
|
Suppose that the binary indexed tree is stored in an array \texttt{b}.
|
||||||
is stored to array \texttt{b} and it consists of indices $1 \ldots n$.
|
The following function \texttt{sum} calculates
|
||||||
|
the sum of elements in the range $[1,k]$:
|
||||||
The function \texttt{sum} calculates the sum of the range $[1,k]$:
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
int sum(int k) {
|
int sum(int k) {
|
||||||
int s = 0;
|
int s = 0;
|
||||||
|
@ -699,7 +700,9 @@ int sum(int k) {
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
The function \texttt{add} increases the value of element $k$ by $x$:
|
The following function \texttt{add} increases the value
|
||||||
|
of the element at position $k$ by $x$
|
||||||
|
($x$ can be positive or negative):
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
void add(int k, int x) {
|
void add(int k, int x) {
|
||||||
while (k <= n) {
|
while (k <= n) {
|
||||||
|
@ -709,11 +712,11 @@ void add(int k, int x) {
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
The time complexity of both above functions is
|
The time complexity of both the functions is
|
||||||
$O(\log n)$ because the functions change $O(\log n)$
|
$O(\log n)$, because the functions access $O(\log n)$
|
||||||
values in the binary indexed tree and each move
|
values in the binary indexed tree, and each transition
|
||||||
to the next index
|
to the next position
|
||||||
takes $O(1)$ time using the bit operation.
|
takes $O(1)$ time using bit operations.
|
||||||
|
|
||||||
\section{Segment tree}
|
\section{Segment tree}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue