1166 lines
37 KiB
TeX
1166 lines
37 KiB
TeX
\chapter{Segment trees revisited}
|
|
|
|
\index{segment tree}
|
|
|
|
A segment tree is a versatile data structure
|
|
that can be used in many different situations.
|
|
However, there are many topics related to segment trees
|
|
that we haven't touched yet.
|
|
Now it's time to learn some more advanced variations
|
|
of segment trees and see their full potential.
|
|
|
|
So far, we have implemented the operations
|
|
of a segment tree by walking \emph{from the bottom to the top},
|
|
from the leaves to the root.
|
|
For example, we have calculated the sum of a range $[a,b]$
|
|
as follows (Chapter 9.3):
|
|
|
|
\begin{lstlisting}
|
|
int sum(int a, int b) {
|
|
a += N; b += N;
|
|
int s = 0;
|
|
while (a <= b) {
|
|
if (a%2 == 1) s += p[a++];
|
|
if (b%2 == 0) s += p[b--];
|
|
a /= 2; b /= 2;
|
|
}
|
|
return s;
|
|
}
|
|
\end{lstlisting}
|
|
However, in more advanced segment trees,
|
|
it's beneficial to implement the operations
|
|
in another way, \emph{from the top to the bottom},
|
|
from the root to the leaves.
|
|
Using this approach, the function becomes as follows:
|
|
|
|
\begin{lstlisting}
|
|
int sum(int a, int b, int k, int x, int y) {
|
|
if (b < x || a > y) return 0;
|
|
if (a == x && b == y) return p[k];
|
|
int d = (y-x+1)/2;
|
|
return sum(a, min(x+d-1,b), 2*k, x, x+d-1) +
|
|
sum(max(x+d,a), b, 2*k+1, x+d, y);
|
|
}
|
|
\end{lstlisting}
|
|
Now we can calulate the sum of the range $[a,b]$
|
|
as follows:
|
|
|
|
\begin{lstlisting}
|
|
int s = sum(a, b, 1, 0, N-1);
|
|
\end{lstlisting}
|
|
The parameter $k$ is the current position
|
|
in array \texttt{p}.
|
|
Initially $k$ equals 1, because we begin
|
|
at the root of the segment tree.
|
|
The range $[x,y]$ corresponds to $k$,
|
|
and is initially $[0,N-1]$.
|
|
If $[a,b]$ is outside $[x,y]$,
|
|
the sum of the range is 0,
|
|
and if $[a,b]$ equals $[x,y]$,
|
|
the sum can be found in array \texttt{p}.
|
|
If $[a,b]$ is completely or partially inside $[x,y]$,
|
|
the search continues recursively to the
|
|
left and right half of $[x,y]$.
|
|
The size of both halves is $d=\frac{1}{2}(y-x+1)$;
|
|
the left half is $[x,x+d-1]$
|
|
and the right half is $[x+d,y]$.
|
|
|
|
The following picture shows how the search proceeds
|
|
when calculating the sum of the marked elements.
|
|
The gray nodes indicate nodes where the recursion
|
|
stops and the sum of the range can be found in array \texttt{p}.
|
|
\\
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.7]
|
|
\fill[color=gray!50] (5,0) rectangle (6,1);
|
|
\draw (0,0) grid (16,1);
|
|
|
|
\node[anchor=center] at (0.5, 0.5) {5};
|
|
\node[anchor=center] at (1.5, 0.5) {8};
|
|
\node[anchor=center] at (2.5, 0.5) {6};
|
|
\node[anchor=center] at (3.5, 0.5) {3};
|
|
\node[anchor=center] at (4.5, 0.5) {2};
|
|
\node[anchor=center] at (5.5, 0.5) {7};
|
|
\node[anchor=center] at (6.5, 0.5) {2};
|
|
\node[anchor=center] at (7.5, 0.5) {6};
|
|
\node[anchor=center] at (8.5, 0.5) {7};
|
|
\node[anchor=center] at (9.5, 0.5) {1};
|
|
\node[anchor=center] at (10.5, 0.5) {7};
|
|
\node[anchor=center] at (11.5, 0.5) {5};
|
|
\node[anchor=center] at (12.5, 0.5) {6};
|
|
\node[anchor=center] at (13.5, 0.5) {2};
|
|
\node[anchor=center] at (14.5, 0.5) {3};
|
|
\node[anchor=center] at (15.5, 0.5) {2};
|
|
|
|
%\node[anchor=center] at (1,2.5) {13};
|
|
|
|
\node[draw, circle] (a) at (1,2.5) {13};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,minimum size=22pt] (b) at (3,2.5) {9};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
\node[draw, circle,minimum size=22pt] (c) at (5,2.5) {9};
|
|
\path[draw,thick,-] (c) -- (4.5,1);
|
|
\path[draw,thick,-] (c) -- (5.5,1);
|
|
\node[draw, circle,fill=gray!50,minimum size=22pt] (d) at (7,2.5) {8};
|
|
\path[draw,thick,-] (d) -- (6.5,1);
|
|
\path[draw,thick,-] (d) -- (7.5,1);
|
|
\node[draw, circle,minimum size=22pt] (e) at (9,2.5) {8};
|
|
\path[draw,thick,-] (e) -- (8.5,1);
|
|
\path[draw,thick,-] (e) -- (9.5,1);
|
|
\node[draw, circle] (f) at (11,2.5) {12};
|
|
\path[draw,thick,-] (f) -- (10.5,1);
|
|
\path[draw,thick,-] (f) -- (11.5,1);
|
|
\node[draw, circle,fill=gray!50,minimum size=22pt] (g) at (13,2.5) {8};
|
|
\path[draw,thick,-] (g) -- (12.5,1);
|
|
\path[draw,thick,-] (g) -- (13.5,1);
|
|
\node[draw, circle,minimum size=22pt] (h) at (15,2.5) {5};
|
|
\path[draw,thick,-] (h) -- (14.5,1);
|
|
\path[draw,thick,-] (h) -- (15.5,1);
|
|
|
|
\node[draw, circle] (i) at (2,4.5) {22};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\node[draw, circle] (j) at (6,4.5) {17};
|
|
\path[draw,thick,-] (j) -- (c);
|
|
\path[draw,thick,-] (j) -- (d);
|
|
\node[draw, circle,fill=gray!50] (k) at (10,4.5) {20};
|
|
\path[draw,thick,-] (k) -- (e);
|
|
\path[draw,thick,-] (k) -- (f);
|
|
\node[draw, circle] (l) at (14,4.5) {13};
|
|
\path[draw,thick,-] (l) -- (g);
|
|
\path[draw,thick,-] (l) -- (h);
|
|
|
|
\node[draw, circle] (m) at (4,6.5) {39};
|
|
\path[draw,thick,-] (m) -- (i);
|
|
\path[draw,thick,-] (m) -- (j);
|
|
\node[draw, circle] (n) at (12,6.5) {33};
|
|
\path[draw,thick,-] (n) -- (k);
|
|
\path[draw,thick,-] (n) -- (l);
|
|
|
|
\node[draw, circle] (o) at (8,8.5) {72};
|
|
\path[draw,thick,-] (o) -- (m);
|
|
\path[draw,thick,-] (o) -- (n);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (o) -- (m);
|
|
\path[draw=red,thick,->,line width=2pt] (o) -- (n);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (m) -- (j);
|
|
\path[draw=red,thick,->,line width=2pt] (j) -- (c);
|
|
\path[draw=red,thick,->,line width=2pt] (j) -- (d);
|
|
\path[draw=red,thick,->,line width=2pt] (c) -- (5.5,1);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (n) -- (k);
|
|
\path[draw=red,thick,->,line width=2pt] (n) -- (l);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (l) -- (g);
|
|
|
|
\draw [decoration={brace}, decorate, line width=0.5mm] (14,-0.25) -- (5,-0.25);
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
Also in this implementation,
|
|
the time complexity of a range query is $O(\log n)$,
|
|
because the total number of processed nodes is $O(\log n)$.
|
|
|
|
\section{Lazy propagation}
|
|
|
|
\index{lazy propagation}
|
|
\index{lazy segment tree}
|
|
|
|
Using \key{lazy propagation}, we can construct
|
|
a segment tree that supports both range updates
|
|
and range queries in $O(\log n)$ time.
|
|
The idea is to perform the updates and queries
|
|
from the top to the bottom, and process the updates
|
|
\emph{lazily} so that they are propagated
|
|
down the tree only when it is necessary.
|
|
|
|
In a lazy segment tree, nodes contain two types of
|
|
information.
|
|
Like in a normal segment tree,
|
|
each node contains the sum or some other value
|
|
of the corresponding subarray.
|
|
In addition, the node may contain information
|
|
related to lazy updates, which has not been
|
|
propagated yet to its children.
|
|
|
|
There are two possible types for range updates:
|
|
\emph{addition} and \emph{insertion}.
|
|
In addition, each element in the range is
|
|
increased by some value,
|
|
and in insertion, each element in the range
|
|
is assigned some value.
|
|
Both operations can be implemented using
|
|
similar ideas, and it's possible to construct
|
|
a tree that supports both the operations
|
|
simultaneously.
|
|
|
|
\subsubsection{Lazy segment tree}
|
|
|
|
Let's consider an example where our goal is to
|
|
construct a segment tree that supports the following operations:
|
|
|
|
\begin{itemize}
|
|
\item increase each element in $[a,b]$ by $u$
|
|
\item calculate the sum of elements in $[a,b]$
|
|
\end{itemize}
|
|
We will construct a tree where each node
|
|
contains two values $s/z$:
|
|
$s$ denotes the sum of elements in the range,
|
|
like in a standard segment tree,
|
|
and $z$ denotes a lazy update,
|
|
which means that all elements in the range
|
|
should be increased by $z$.
|
|
In the following tree, $z=0$ for all nodes,
|
|
so there are no lazy updates.
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.7]
|
|
\draw (0,0) grid (16,1);
|
|
|
|
\node[anchor=center] at (0.5, 0.5) {5};
|
|
\node[anchor=center] at (1.5, 0.5) {8};
|
|
\node[anchor=center] at (2.5, 0.5) {6};
|
|
\node[anchor=center] at (3.5, 0.5) {3};
|
|
\node[anchor=center] at (4.5, 0.5) {2};
|
|
\node[anchor=center] at (5.5, 0.5) {7};
|
|
\node[anchor=center] at (6.5, 0.5) {2};
|
|
\node[anchor=center] at (7.5, 0.5) {6};
|
|
\node[anchor=center] at (8.5, 0.5) {7};
|
|
\node[anchor=center] at (9.5, 0.5) {1};
|
|
\node[anchor=center] at (10.5, 0.5) {7};
|
|
\node[anchor=center] at (11.5, 0.5) {5};
|
|
\node[anchor=center] at (12.5, 0.5) {6};
|
|
\node[anchor=center] at (13.5, 0.5) {2};
|
|
\node[anchor=center] at (14.5, 0.5) {3};
|
|
\node[anchor=center] at (15.5, 0.5) {2};
|
|
|
|
\node[draw, circle] (a) at (1,2.5) {13/0};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,minimum size=32pt] (b) at (3,2.5) {9/0};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
\node[draw, circle,minimum size=32pt] (c) at (5,2.5) {9/0};
|
|
\path[draw,thick,-] (c) -- (4.5,1);
|
|
\path[draw,thick,-] (c) -- (5.5,1);
|
|
\node[draw, circle,minimum size=32pt] (d) at (7,2.5) {8/0};
|
|
\path[draw,thick,-] (d) -- (6.5,1);
|
|
\path[draw,thick,-] (d) -- (7.5,1);
|
|
\node[draw, circle,minimum size=32pt] (e) at (9,2.5) {8/0};
|
|
\path[draw,thick,-] (e) -- (8.5,1);
|
|
\path[draw,thick,-] (e) -- (9.5,1);
|
|
\node[draw, circle] (f) at (11,2.5) {12/0};
|
|
\path[draw,thick,-] (f) -- (10.5,1);
|
|
\path[draw,thick,-] (f) -- (11.5,1);
|
|
\node[draw, circle,minimum size=32pt] (g) at (13,2.5) {8/0};
|
|
\path[draw,thick,-] (g) -- (12.5,1);
|
|
\path[draw,thick,-] (g) -- (13.5,1);
|
|
\node[draw, circle,minimum size=32pt] (h) at (15,2.5) {5/0};
|
|
\path[draw,thick,-] (h) -- (14.5,1);
|
|
\path[draw,thick,-] (h) -- (15.5,1);
|
|
|
|
\node[draw, circle] (i) at (2,4.5) {22/0};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\node[draw, circle] (j) at (6,4.5) {17/0};
|
|
\path[draw,thick,-] (j) -- (c);
|
|
\path[draw,thick,-] (j) -- (d);
|
|
\node[draw, circle] (k) at (10,4.5) {20/0};
|
|
\path[draw,thick,-] (k) -- (e);
|
|
\path[draw,thick,-] (k) -- (f);
|
|
\node[draw, circle] (l) at (14,4.5) {13/0};
|
|
\path[draw,thick,-] (l) -- (g);
|
|
\path[draw,thick,-] (l) -- (h);
|
|
|
|
\node[draw, circle] (m) at (4,6.5) {39/0};
|
|
\path[draw,thick,-] (m) -- (i);
|
|
\path[draw,thick,-] (m) -- (j);
|
|
\node[draw, circle] (n) at (12,6.5) {33/0};
|
|
\path[draw,thick,-] (n) -- (k);
|
|
\path[draw,thick,-] (n) -- (l);
|
|
|
|
\node[draw, circle] (o) at (8,8.5) {72/0};
|
|
\path[draw,thick,-] (o) -- (m);
|
|
\path[draw,thick,-] (o) -- (n);
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
|
|
When a range $[a,b]$ is increased by $u$,
|
|
we walk from the root towards the leaves
|
|
and modify the nodes in the tree as follows:
|
|
If the range $[x,y]$ of a node is
|
|
completely inside the range $[a,b]$,
|
|
we increase the $z$ value of the node by $u$ and stop.
|
|
However, if $[x,y]$ only partially belongs to $[a,b]$,
|
|
we increase the $s$ value of the node by $hu$,
|
|
where $h$ is the size of the intersection of $[a,b]$
|
|
and $[x,y]$, and continue our walk recursively in the tree.
|
|
|
|
For example, the following picture shows the tree after
|
|
increasing the elements in the range marked at the bottom by 2:
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.7]
|
|
\fill[color=gray!50] (5,0) rectangle (6,1);
|
|
\draw (0,0) grid (16,1);
|
|
|
|
\node[anchor=center] at (0.5, 0.5) {5};
|
|
\node[anchor=center] at (1.5, 0.5) {8};
|
|
\node[anchor=center] at (2.5, 0.5) {6};
|
|
\node[anchor=center] at (3.5, 0.5) {3};
|
|
\node[anchor=center] at (4.5, 0.5) {2};
|
|
\node[anchor=center] at (5.5, 0.5) {9};
|
|
\node[anchor=center] at (6.5, 0.5) {2};
|
|
\node[anchor=center] at (7.5, 0.5) {6};
|
|
\node[anchor=center] at (8.5, 0.5) {7};
|
|
\node[anchor=center] at (9.5, 0.5) {1};
|
|
\node[anchor=center] at (10.5, 0.5) {7};
|
|
\node[anchor=center] at (11.5, 0.5) {5};
|
|
\node[anchor=center] at (12.5, 0.5) {6};
|
|
\node[anchor=center] at (13.5, 0.5) {2};
|
|
\node[anchor=center] at (14.5, 0.5) {3};
|
|
\node[anchor=center] at (15.5, 0.5) {2};
|
|
|
|
\node[draw, circle] (a) at (1,2.5) {13/0};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,minimum size=32pt] (b) at (3,2.5) {9/0};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
\node[draw, circle,minimum size=32pt] (c) at (5,2.5) {11/0};
|
|
\path[draw,thick,-] (c) -- (4.5,1);
|
|
\path[draw,thick,-] (c) -- (5.5,1);
|
|
\node[draw, circle,fill=gray!50,minimum size=32pt] (d) at (7,2.5) {8/2};
|
|
\path[draw,thick,-] (d) -- (6.5,1);
|
|
\path[draw,thick,-] (d) -- (7.5,1);
|
|
\node[draw, circle,minimum size=32pt] (e) at (9,2.5) {8/0};
|
|
\path[draw,thick,-] (e) -- (8.5,1);
|
|
\path[draw,thick,-] (e) -- (9.5,1);
|
|
\node[draw, circle] (f) at (11,2.5) {12/0};
|
|
\path[draw,thick,-] (f) -- (10.5,1);
|
|
\path[draw,thick,-] (f) -- (11.5,1);
|
|
\node[draw, circle,fill=gray!50,minimum size=32pt] (g) at (13,2.5) {8/2};
|
|
\path[draw,thick,-] (g) -- (12.5,1);
|
|
\path[draw,thick,-] (g) -- (13.5,1);
|
|
\node[draw, circle,minimum size=32pt] (h) at (15,2.5) {5/0};
|
|
\path[draw,thick,-] (h) -- (14.5,1);
|
|
\path[draw,thick,-] (h) -- (15.5,1);
|
|
|
|
\node[draw, circle] (i) at (2,4.5) {22/0};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\node[draw, circle] (j) at (6,4.5) {23/0};
|
|
\path[draw,thick,-] (j) -- (c);
|
|
\path[draw,thick,-] (j) -- (d);
|
|
\node[draw, circle,fill=gray!50] (k) at (10,4.5) {20/2};
|
|
\path[draw,thick,-] (k) -- (e);
|
|
\path[draw,thick,-] (k) -- (f);
|
|
\node[draw, circle] (l) at (14,4.5) {17/0};
|
|
\path[draw,thick,-] (l) -- (g);
|
|
\path[draw,thick,-] (l) -- (h);
|
|
|
|
\node[draw, circle] (m) at (4,6.5) {45/0};
|
|
\path[draw,thick,-] (m) -- (i);
|
|
\path[draw,thick,-] (m) -- (j);
|
|
\node[draw, circle] (n) at (12,6.5) {45/0};
|
|
\path[draw,thick,-] (n) -- (k);
|
|
\path[draw,thick,-] (n) -- (l);
|
|
|
|
\node[draw, circle] (o) at (8,8.5) {90/0};
|
|
\path[draw,thick,-] (o) -- (m);
|
|
\path[draw,thick,-] (o) -- (n);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (o) -- (m);
|
|
\path[draw=red,thick,->,line width=2pt] (o) -- (n);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (m) -- (j);
|
|
\path[draw=red,thick,->,line width=2pt] (j) -- (c);
|
|
\path[draw=red,thick,->,line width=2pt] (j) -- (d);
|
|
\path[draw=red,thick,->,line width=2pt] (c) -- (5.5,1);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (n) -- (k);
|
|
\path[draw=red,thick,->,line width=2pt] (n) -- (l);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (l) -- (g);
|
|
|
|
\draw [decoration={brace}, decorate, line width=0.5mm] (14,-0.25) -- (5,-0.25);
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
|
|
We also calculate the sum in a range $[a,b]$
|
|
by walking in the tree from the root towards the leaves.
|
|
If the range $[x,y]$ of a node completely belongs
|
|
to $[a,b]$, we add the $s$ value of the node to the sum.
|
|
Otherwise, we continue the search recursively
|
|
downwards in the tree.
|
|
|
|
Always before processing a node,
|
|
the value of the lazy update is propagated
|
|
to the children of the node.
|
|
This happens both in a range update
|
|
and a range query.
|
|
The idea is that the lazy update will be propagated
|
|
downwards only when it is necessary,
|
|
so that the operations are always efficient.
|
|
|
|
The following picture shows how the tree changes
|
|
when we calculate the sum in the marked range:
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.7]
|
|
\draw (0,0) grid (16,1);
|
|
|
|
\node[anchor=center] at (0.5, 0.5) {5};
|
|
\node[anchor=center] at (1.5, 0.5) {8};
|
|
\node[anchor=center] at (2.5, 0.5) {6};
|
|
\node[anchor=center] at (3.5, 0.5) {3};
|
|
\node[anchor=center] at (4.5, 0.5) {2};
|
|
\node[anchor=center] at (5.5, 0.5) {9};
|
|
\node[anchor=center] at (6.5, 0.5) {2};
|
|
\node[anchor=center] at (7.5, 0.5) {6};
|
|
\node[anchor=center] at (8.5, 0.5) {7};
|
|
\node[anchor=center] at (9.5, 0.5) {1};
|
|
\node[anchor=center] at (10.5, 0.5) {7};
|
|
\node[anchor=center] at (11.5, 0.5) {5};
|
|
\node[anchor=center] at (12.5, 0.5) {6};
|
|
\node[anchor=center] at (13.5, 0.5) {2};
|
|
\node[anchor=center] at (14.5, 0.5) {3};
|
|
\node[anchor=center] at (15.5, 0.5) {2};
|
|
|
|
\node[draw, circle] (a) at (1,2.5) {13/0};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,minimum size=32pt] (b) at (3,2.5) {9/0};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
\node[draw, circle,minimum size=32pt] (c) at (5,2.5) {11/0};
|
|
\path[draw,thick,-] (c) -- (4.5,1);
|
|
\path[draw,thick,-] (c) -- (5.5,1);
|
|
\node[draw, circle,minimum size=32pt] (d) at (7,2.5) {8/2};
|
|
\path[draw,thick,-] (d) -- (6.5,1);
|
|
\path[draw,thick,-] (d) -- (7.5,1);
|
|
\node[draw, circle,minimum size=32pt] (e) at (9,2.5) {8/2};
|
|
\path[draw,thick,-] (e) -- (8.5,1);
|
|
\path[draw,thick,-] (e) -- (9.5,1);
|
|
\node[draw, circle,fill=gray!50,] (f) at (11,2.5) {12/2};
|
|
\path[draw,thick,-] (f) -- (10.5,1);
|
|
\path[draw,thick,-] (f) -- (11.5,1);
|
|
\node[draw, circle,fill=gray!50,minimum size=32pt] (g) at (13,2.5) {8/2};
|
|
\path[draw,thick,-] (g) -- (12.5,1);
|
|
\path[draw,thick,-] (g) -- (13.5,1);
|
|
\node[draw, circle,minimum size=32pt] (h) at (15,2.5) {5/0};
|
|
\path[draw,thick,-] (h) -- (14.5,1);
|
|
\path[draw,thick,-] (h) -- (15.5,1);
|
|
|
|
\node[draw, circle] (i) at (2,4.5) {22/0};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\node[draw, circle] (j) at (6,4.5) {23/0};
|
|
\path[draw,thick,-] (j) -- (c);
|
|
\path[draw,thick,-] (j) -- (d);
|
|
\node[draw, circle] (k) at (10,4.5) {28/0};
|
|
\path[draw,thick,-] (k) -- (e);
|
|
\path[draw,thick,-] (k) -- (f);
|
|
\node[draw, circle] (l) at (14,4.5) {17/0};
|
|
\path[draw,thick,-] (l) -- (g);
|
|
\path[draw,thick,-] (l) -- (h);
|
|
|
|
\node[draw, circle] (m) at (4,6.5) {45/0};
|
|
\path[draw,thick,-] (m) -- (i);
|
|
\path[draw,thick,-] (m) -- (j);
|
|
\node[draw, circle] (n) at (12,6.5) {45/0};
|
|
\path[draw,thick,-] (n) -- (k);
|
|
\path[draw,thick,-] (n) -- (l);
|
|
|
|
\node[draw, circle] (o) at (8,8.5) {90/0};
|
|
\path[draw,thick,-] (o) -- (m);
|
|
\path[draw,thick,-] (o) -- (n);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (o) -- (n);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (n) -- (k);
|
|
\path[draw=red,thick,->,line width=2pt] (n) -- (l);
|
|
|
|
\path[draw=red,thick,->,line width=2pt] (k) -- (f);
|
|
\path[draw=red,thick,->,line width=2pt] (l) -- (g);
|
|
|
|
\draw [decoration={brace}, decorate, line width=0.5mm] (14,-0.25) -- (10,-0.25);
|
|
|
|
\draw[color=blue,thick] (8,1.5) rectangle (12,5.5);
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
The result of this query was that a lazy update was
|
|
propagated downwards in the nodes that are inside the rectangle.
|
|
It was necessary to propagate the lazy update,
|
|
because some of the updated elements were inside the range.
|
|
|
|
Note that sometimes it's necessary to combine lazy updates.
|
|
This happens when a node already has a lazy update,
|
|
and another lazy update will be added to it.
|
|
In the above tree, it's easy to combine lazy updates
|
|
because updates $z_1$ and $z_2$ combined equal to update $z_1+z_2$.
|
|
|
|
\subsubsection{Polynomial update}
|
|
|
|
A lazy update can be generalized so that it's
|
|
allowed to update a range by a polynomial
|
|
\[p(u) = t_k u^k + t_{k-1} u^{k-1} + \cdots + t_0.\]
|
|
|
|
Here, the update for the first element in the range is $p(0)$,
|
|
for the second element $p(1)$, etc., so the update
|
|
at index $i$ in range $[a,b]$ is $p(i-a)$.
|
|
For example, adding a polynomial $p(u)=u+1$
|
|
to range $[a,b]$ means that the element at index $a$
|
|
increases by 1, the element at index $a+1$
|
|
increases by 2, etc.
|
|
|
|
A polynomial update can be supported by
|
|
storing $k+2$ values to each node where $k$
|
|
equals the degree of the polynomial.
|
|
The value $s$ is the sum of the elements in the range,
|
|
and values $z_0,z_1,\ldots,z_k$ are the coefficients
|
|
of a polynomial that corresponds to a lazy update.
|
|
|
|
Now, the sum of $[x,y]$ is
|
|
\[s+\sum_{u=0}^{y-x} z_k u^k + z_{k-1} u^{k-1} + \cdots + z_0,\]
|
|
that can be efficiently calculated using sum formulas
|
|
For example, the value $z_0$ corresponds to the sum
|
|
$(y-x+1)z_0$, and the value $z_1 u$ corresponds to the sum
|
|
\[z_1(0+1+\cdots+y-x) = z_1 \frac{(y-x)(y-x+1)}{2} .\]
|
|
|
|
When propagating an update in the tree,
|
|
the indices of the polynomial $p(u)$ change,
|
|
because in each range $[x,y]$,
|
|
the values are
|
|
calculated for $x=0,1,\ldots,y-x$.
|
|
However, this is not a problem, because
|
|
$p'(u)=p(u+h)$ is a polynomial
|
|
of equal degree as $p(u)$.
|
|
For example, if $p(u)=t_2 u^2+t_1 u-t_0$, then
|
|
\[p'(u)=t_2(u+h)^2+t_1(u+h)-t_0=t_2 u^2 + (2ht_2+t_1)u+t_2h^2+t_1h-t_0.\]
|
|
|
|
\section{Dynamic trees}
|
|
|
|
\index{dynamic segment tree}
|
|
|
|
A regular segment tree is static,
|
|
which means that each node has a fixed position
|
|
in the array and storing the tree requires
|
|
a fixed amount of memory.
|
|
However, if most nodes are empty, such an
|
|
implementation wastes memory.
|
|
In a \key{dynamic segment tree},
|
|
memory is reserved only for nodes that
|
|
are actually needed.
|
|
|
|
The nodes can be represented as structs as follows:
|
|
|
|
\begin{lstlisting}
|
|
struct node {
|
|
int s;
|
|
int x, y;
|
|
node *l, *r;
|
|
node(int x, int a, int b) : s(s), x(x), y(y) {}
|
|
};
|
|
\end{lstlisting}
|
|
Here $s$ is the value of the node,
|
|
$[x,y]$ is the corresponding range,
|
|
and $l$ and $r$ point to the left
|
|
and right subtree.
|
|
|
|
After this, nodes can be manipulated as follows:
|
|
|
|
\begin{lstlisting}
|
|
// create new node
|
|
node *u = new node(0, 0, 15);
|
|
// change value
|
|
u->s = 5;
|
|
\end{lstlisting}
|
|
|
|
\subsubsection{Sparse segment tree}
|
|
|
|
\index{sparse segment tree}
|
|
|
|
A dynamic segment tree is useful if
|
|
the range $[0,N-1]$ covered by the tree is \emph{sparse},
|
|
which means that $N$ is large but only a
|
|
small portion of the indices are used.
|
|
While a regular segment tree uses $O(n)$ memory,
|
|
a dynamic segment tree only uses $O(n \log N)$ memory,
|
|
where $n$ is the number of indices used.
|
|
|
|
A \key{sparse segment tree} is initially empty
|
|
and its only node is $[0,N-1]$.
|
|
When the tree changes, new nodes are added dynamically
|
|
always when they are needed because of new indices.
|
|
For example, if $N=16$, and the elements
|
|
in indices 3 and 10 have been changes,
|
|
the tree contains the following nodes:
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.9]
|
|
\scriptsize
|
|
\node[draw, circle,minimum size=35pt] (1) at (0,0) {$[0,15]$};
|
|
\node[draw, circle,minimum size=35pt] (2) at (-4,-2) {$[0,7]$};
|
|
\node[draw, circle,minimum size=35pt] (3) at (-6,-4) {$[0,3]$};
|
|
\node[draw, circle,minimum size=35pt] (4) at (-4,-6) {$[2,3]$};
|
|
\node[draw, circle,minimum size=35pt] (5) at (-2,-8) {$[3]$};
|
|
\node[draw, circle,minimum size=35pt] (6) at (4,-2) {$[8,15]$};
|
|
\node[draw, circle,minimum size=35pt] (7) at (2,-4) {$[8,11]$};
|
|
\node[draw, circle,minimum size=35pt] (8) at (4,-6) {$[10,11]$};
|
|
\node[draw, circle,minimum size=35pt] (9) at (2,-8) {$[10]$};
|
|
|
|
\path[draw,thick,->] (1) -- (2);
|
|
\path[draw,thick,->] (2) -- (3);
|
|
\path[draw,thick,->] (3) -- (4);
|
|
\path[draw,thick,->] (4) -- (5);
|
|
|
|
\path[draw,thick,->] (1) -- (6);
|
|
\path[draw,thick,->] (6) -- (7);
|
|
\path[draw,thick,->] (7) -- (8);
|
|
\path[draw,thick,->] (8) -- (9);
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
|
|
Any path from the root to a leaf contains
|
|
$O(\log N)$ nodes,
|
|
so each change adds at most $O(\log n)$
|
|
new nodes to the tree.
|
|
Thus, after $n$ changes, the tree contains
|
|
at most $O(n \log N)$ nodes.
|
|
|
|
Note that if all indices of the elements
|
|
are known at the beginning of the algorithm,
|
|
a dynamic segment tree is not needed,
|
|
but we can use a regular segment tree with
|
|
index compression (Chapter 9.4).
|
|
However, this is not possible if the indices
|
|
are generated during the algorithm.
|
|
|
|
\subsubsection{Persistent segment tree}
|
|
|
|
\index{persistent segment tree}
|
|
\index{version history}
|
|
|
|
Using a dynamic implementation,
|
|
it is also possible to create a
|
|
\key{persistent segment tree} that stores
|
|
the \key{version history} of the tree.
|
|
In such an implementation, we can
|
|
efficiently access
|
|
all versions of the tree that have been
|
|
existed during the algorithm.
|
|
|
|
When the version history is available,
|
|
we can access all versions of the tree
|
|
like a regular segment tree, because their
|
|
structure is stored.
|
|
We can also derive new trees from the history
|
|
and further manipulate them.
|
|
|
|
Consider the following sequence of updates,
|
|
where red nodes change in an update
|
|
and other nodes remain the same:
|
|
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.8]
|
|
\node[draw, circle,minimum size=13pt] (1a) at (3,0) {};
|
|
\node[draw, circle,minimum size=13pt] (2a) at (2,-1) {};
|
|
\node[draw, circle,minimum size=13pt] (3a) at (4,-1) {};
|
|
\node[draw, circle,minimum size=13pt] (4a) at (1.5,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (5a) at (2.5,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (6a) at (3.5,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (7a) at (4.5,-2) {};
|
|
\path[draw,thick,->] (1a) -- (2a);
|
|
\path[draw,thick,->] (1a) -- (3a);
|
|
\path[draw,thick,->] (2a) -- (4a);
|
|
\path[draw,thick,->] (2a) -- (5a);
|
|
\path[draw,thick,->] (3a) -- (6a);
|
|
\path[draw,thick,->] (3a) -- (7a);
|
|
|
|
\node[draw, circle,minimum size=13pt,fill=red] (1b) at (3+5,0) {};
|
|
\node[draw, circle,minimum size=13pt,fill=red] (2b) at (2+5,-1) {};
|
|
\node[draw, circle,minimum size=13pt] (3b) at (4+5,-1) {};
|
|
\node[draw, circle,minimum size=13pt] (4b) at (1.5+5,-2) {};
|
|
\node[draw, circle,minimum size=13pt,fill=red] (5b) at (2.5+5,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (6b) at (3.5+5,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (7b) at (4.5+5,-2) {};
|
|
\path[draw,thick,->] (1b) -- (2b);
|
|
\path[draw,thick,->] (1b) -- (3b);
|
|
\path[draw,thick,->] (2b) -- (4b);
|
|
\path[draw,thick,->] (2b) -- (5b);
|
|
\path[draw,thick,->] (3b) -- (6b);
|
|
\path[draw,thick,->] (3b) -- (7b);
|
|
|
|
\node[draw, circle,minimum size=13pt,fill=red] (1c) at (3+10,0) {};
|
|
\node[draw, circle,minimum size=13pt] (2c) at (2+10,-1) {};
|
|
\node[draw, circle,minimum size=13pt,fill=red] (3c) at (4+10,-1) {};
|
|
\node[draw, circle,minimum size=13pt] (4c) at (1.5+10,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (5c) at (2.5+10,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (6c) at (3.5+10,-2) {};
|
|
\node[draw, circle,minimum size=13pt,fill=red] (7c) at (4.5+10,-2) {};
|
|
\path[draw,thick,->] (1c) -- (2c);
|
|
\path[draw,thick,->] (1c) -- (3c);
|
|
\path[draw,thick,->] (2c) -- (4c);
|
|
\path[draw,thick,->] (2c) -- (5c);
|
|
\path[draw,thick,->] (3c) -- (6c);
|
|
\path[draw,thick,->] (3c) -- (7c);
|
|
|
|
\node at (3,-3) {step 1};
|
|
\node at (3+5,-3) {step 2};
|
|
\node at (3+10,-3) {step 3};
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
After each update, most nodes in the tree
|
|
remain the same,
|
|
so an efficient way to store the version history
|
|
is to represent each tree in the history as a combination
|
|
of new nodes and subtrees of previous trees.
|
|
In this case, the version history can be
|
|
stored as follows:
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.8]
|
|
\path[use as bounding box] (0, 1) rectangle (16, -3.5);
|
|
|
|
\node[draw, circle,minimum size=13pt] (1a) at (3,0) {};
|
|
\node[draw, circle,minimum size=13pt] (2a) at (2,-1) {};
|
|
\node[draw, circle,minimum size=13pt] (3a) at (4,-1) {};
|
|
\node[draw, circle,minimum size=13pt] (4a) at (1.5,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (5a) at (2.5,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (6a) at (3.5,-2) {};
|
|
\node[draw, circle,minimum size=13pt] (7a) at (4.5,-2) {};
|
|
\path[draw,thick,->] (1a) -- (2a);
|
|
\path[draw,thick,->] (1a) -- (3a);
|
|
\path[draw,thick,->] (2a) -- (4a);
|
|
\path[draw,thick,->] (2a) -- (5a);
|
|
\path[draw,thick,->] (3a) -- (6a);
|
|
\path[draw,thick,->] (3a) -- (7a);
|
|
|
|
\node[draw, circle,minimum size=13pt,fill=red] (1b) at (3+5,0) {};
|
|
\node[draw, circle,minimum size=13pt,fill=red] (2b) at (2+5,-1) {};
|
|
\node[draw, circle,minimum size=13pt,fill=red] (5b) at (2.5+5,-2) {};
|
|
\path[draw,thick,->] (1b) -- (2b);
|
|
|
|
\draw[thick,->] (1b) .. controls (3+5+2,0-1) and (3+5,2.5) .. (3a);
|
|
|
|
\draw[thick,->] (2b) .. controls (2+5-0.5,-1-0.5) and (2,4.5) .. (4a);
|
|
|
|
|
|
\path[draw,thick,->] (2b) -- (5b);
|
|
|
|
\node[draw, circle,minimum size=13pt,fill=red] (1c) at (3+10,0) {};
|
|
\node[draw, circle,minimum size=13pt,fill=red] (3c) at (4+10,-1) {};
|
|
\node[draw, circle,minimum size=13pt,fill=red] (7c) at (4.5+10,-2) {};
|
|
\path[draw,thick,->] (1c) -- (2b);
|
|
\path[draw,thick,->] (1c) -- (3c);
|
|
|
|
\draw[thick,->] (3c) .. controls (2.5+5,-3) and (3.5,-3) .. (6a);
|
|
|
|
\path[draw,thick,->] (3c) -- (7c);
|
|
|
|
\node at (3,-3) {step 1};
|
|
\node at (3+5,-3) {step 2};
|
|
\node at (3+10,-3) {step 3};
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
|
|
The structure of each version of the tree in the history can be
|
|
reconstructed by following the pointers from the root.
|
|
Each update only adds $O(\log N)$ new nodes to the tree
|
|
when the indices are $[0,N-1]$,
|
|
so it is possible to store the full version history
|
|
of the tree.
|
|
|
|
\section{Data structures}
|
|
|
|
Insted of a single value, a node in a segment tree
|
|
can also contain a data structure that maintains information
|
|
about the corresponding range.
|
|
In this case, the operations of the tree take
|
|
$O(f(n) \log n)$ time, where $f(n)$ is
|
|
the time needed for retrieving or updating the
|
|
information in a single node.
|
|
|
|
As an example, consider a segment tree that
|
|
supports queries of the form
|
|
''how many times does element $x$ appear
|
|
in range $[a,b]$?''
|
|
For example, element 1 appears three times
|
|
in the following subarray:
|
|
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.7]
|
|
\fill[lightgray] (1,0) rectangle (6,1);
|
|
\draw (0,0) grid (8,1);
|
|
|
|
\node[anchor=center] at (0.5, 0.5) {3};
|
|
\node[anchor=center] at (1.5, 0.5) {1};
|
|
\node[anchor=center] at (2.5, 0.5) {2};
|
|
\node[anchor=center] at (3.5, 0.5) {3};
|
|
\node[anchor=center] at (4.5, 0.5) {1};
|
|
\node[anchor=center] at (5.5, 0.5) {1};
|
|
\node[anchor=center] at (6.5, 0.5) {1};
|
|
\node[anchor=center] at (7.5, 0.5) {2};
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
|
|
The idea is to construct a segment tree
|
|
where each node has a data structure
|
|
that can return the number of any element $x$
|
|
in the range.
|
|
Using such a segment tree,
|
|
the answer for a query can be calculated
|
|
by combining the results from the nodes
|
|
that belong to the range.
|
|
|
|
For example, the following segment tree
|
|
corresponds to the above array:
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.7]
|
|
|
|
\node[draw, rectangle] (a) at (1,2.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{r}
|
|
3 \\
|
|
\hline
|
|
1 \\
|
|
\end{tabular}};
|
|
\node[draw, rectangle] (b) at (3,2.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{r}
|
|
1 \\
|
|
\hline
|
|
1 \\
|
|
\end{tabular}};
|
|
\node[draw, rectangle] (c) at (5,2.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{r}
|
|
2 \\
|
|
\hline
|
|
1 \\
|
|
\end{tabular}};
|
|
\node[draw, rectangle] (d) at (7,2.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{r}
|
|
3 \\
|
|
\hline
|
|
1 \\
|
|
\end{tabular}};
|
|
\node[draw, rectangle] (e) at (9,2.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{r}
|
|
1 \\
|
|
\hline
|
|
1 \\
|
|
\end{tabular}};
|
|
\node[draw, rectangle] (f) at (11,2.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{r}
|
|
1 \\
|
|
\hline
|
|
1 \\
|
|
\end{tabular}};
|
|
\node[draw, rectangle] (g) at (13,2.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{r}
|
|
1 \\
|
|
\hline
|
|
1 \\
|
|
\end{tabular}};
|
|
\node[draw, rectangle] (h) at (15,2.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{r}
|
|
2 \\
|
|
\hline
|
|
1 \\
|
|
\end{tabular}};
|
|
|
|
\node[draw, rectangle] (i) at (2,4.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{rr}
|
|
1 & 3 \\
|
|
\hline
|
|
1 & 1 \\
|
|
\end{tabular}};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\node[draw, rectangle] (j) at (6,4.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{rr}
|
|
2 & 3 \\
|
|
\hline
|
|
1 & 1 \\
|
|
\end{tabular}};
|
|
\path[draw,thick,-] (j) -- (c);
|
|
\path[draw,thick,-] (j) -- (d);
|
|
\node[draw, rectangle] (k) at (10,4.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{r}
|
|
1 \\
|
|
\hline
|
|
2 \\
|
|
\end{tabular}};
|
|
\path[draw,thick,-] (k) -- (e);
|
|
\path[draw,thick,-] (k) -- (f);
|
|
\node[draw, rectangle] (l) at (14,4.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{rr}
|
|
1 & 2 \\
|
|
\hline
|
|
1 & 1 \\
|
|
\end{tabular}};
|
|
\path[draw,thick,-] (l) -- (g);
|
|
\path[draw,thick,-] (l) -- (h);
|
|
|
|
\node[draw, rectangle] (m) at (4,6.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{rrr}
|
|
1 & 2 & 3 \\
|
|
\hline
|
|
1 & 1 & 2 \\
|
|
\end{tabular}};
|
|
\path[draw,thick,-] (m) -- (i);
|
|
\path[draw,thick,-] (m) -- (j);
|
|
\node[draw, rectangle] (n) at (12,6.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{rr}
|
|
1 & 2 \\
|
|
\hline
|
|
3 & 1 \\
|
|
\end{tabular}};
|
|
\path[draw,thick,-] (n) -- (k);
|
|
\path[draw,thick,-] (n) -- (l);
|
|
|
|
\node[draw, rectangle] (o) at (8,8.5)
|
|
{
|
|
\footnotesize
|
|
\begin{tabular}{rrr}
|
|
1 & 2 & 3 \\
|
|
\hline
|
|
4 & 2 & 2 \\
|
|
\end{tabular}};
|
|
\path[draw,thick,-] (o) -- (m);
|
|
\path[draw,thick,-] (o) -- (n);
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
|
|
Each node in the tree should contain
|
|
an appropriate data structure, for example a
|
|
\texttt{map} structure.
|
|
In this case, the time needed for accessing
|
|
a node is $O(\log n)$, so the total time complexity
|
|
of a query is $O(\log^2 n)$.
|
|
|
|
Data structures in nodes increase the memory usage
|
|
of the tree.
|
|
In this example, $O(n \log n)$ memory is needed,
|
|
because the tree consists of $O(\log n)$ levels,
|
|
and the map structures contain a total
|
|
of $O(n)$ values at each level.
|
|
|
|
\section{Two-dimensionality}
|
|
|
|
\index{two-dimensional segment tree}
|
|
|
|
A \key{two-dimensional segment tree} supports
|
|
queries about rectangles in a two-dimensional array.
|
|
Such a segment tree can be implemented as
|
|
nested segmenet trees: a big tree corresponds to the
|
|
rows in the array, and each node contains a small tree
|
|
that corresponds to a column.
|
|
|
|
For example, in the array
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.7]
|
|
\draw (0,0) grid (4,4);
|
|
|
|
\node[anchor=center] at (0.5, 0.5) {8};
|
|
\node[anchor=center] at (1.5, 0.5) {5};
|
|
\node[anchor=center] at (2.5, 0.5) {3};
|
|
\node[anchor=center] at (3.5, 0.5) {8};
|
|
|
|
\node[anchor=center] at (0.5, 1.5) {3};
|
|
\node[anchor=center] at (1.5, 1.5) {9};
|
|
\node[anchor=center] at (2.5, 1.5) {7};
|
|
\node[anchor=center] at (3.5, 1.5) {1};
|
|
|
|
\node[anchor=center] at (0.5, 2.5) {8};
|
|
\node[anchor=center] at (1.5, 2.5) {7};
|
|
\node[anchor=center] at (2.5, 2.5) {5};
|
|
\node[anchor=center] at (3.5, 2.5) {2};
|
|
|
|
\node[anchor=center] at (0.5, 3.5) {7};
|
|
\node[anchor=center] at (1.5, 3.5) {6};
|
|
\node[anchor=center] at (2.5, 3.5) {1};
|
|
\node[anchor=center] at (3.5, 3.5) {6};
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
sums of rectangles can be calculated
|
|
from the following segment tree:
|
|
\begin{center}
|
|
\begin{tikzpicture}[scale=0.4]
|
|
\footnotesize
|
|
\begin{scope}[shift={(-12,0)}]
|
|
\draw (-1,-1) rectangle (5,6);
|
|
\draw (0,0) grid (4,1);
|
|
\node[anchor=center,scale=0.8] at (0.5, 0.5) {7};
|
|
\node[anchor=center,scale=0.8] at (1.5, 0.5) {6};
|
|
\node[anchor=center,scale=0.8] at (2.5, 0.5) {1};
|
|
\node[anchor=center,scale=0.8] at (3.5, 0.5) {6};
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (a) at (1,2.5) {13};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,scale=0.8,inner sep=2.5pt] (b) at (3,2.5) {7};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (i) at (2,4.5) {20};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\end{scope}
|
|
\begin{scope}[shift={(-4,0)}]
|
|
\draw (-1,-1) rectangle (5,6);
|
|
\draw (0,0) grid (4,1);
|
|
\node[anchor=center,scale=0.8] at (0.5, 0.5) {8};
|
|
\node[anchor=center,scale=0.8] at (1.5, 0.5) {7};
|
|
\node[anchor=center,scale=0.8] at (2.5, 0.5) {5};
|
|
\node[anchor=center,scale=0.8] at (3.5, 0.5) {2};
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (a) at (1,2.5) {15};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,scale=0.8,inner sep=2.5pt] (b) at (3,2.5) {7};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (i) at (2,4.5) {22};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\end{scope}
|
|
\begin{scope}[shift={(4,0)}]
|
|
\draw (-1,-1) rectangle (5,6);
|
|
\draw (0,0) grid (4,1);
|
|
\node[anchor=center,scale=0.8] at (0.5, 0.5) {3};
|
|
\node[anchor=center,scale=0.8] at (1.5, 0.5) {9};
|
|
\node[anchor=center,scale=0.8] at (2.5, 0.5) {7};
|
|
\node[anchor=center,scale=0.8] at (3.5, 0.5) {1};
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (a) at (1,2.5) {12};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,scale=0.8,inner sep=2.5pt] (b) at (3,2.5) {8};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (i) at (2,4.5) {20};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\end{scope}
|
|
\begin{scope}[shift={(12,0)}]
|
|
\draw (-1,-1) rectangle (5,6);
|
|
\draw (0,0) grid (4,1);
|
|
\node[anchor=center,scale=0.8] at (0.5, 0.5) {8};
|
|
\node[anchor=center,scale=0.8] at (1.5, 0.5) {5};
|
|
\node[anchor=center,scale=0.8] at (2.5, 0.5) {3};
|
|
\node[anchor=center,scale=0.8] at (3.5, 0.5) {8};
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (a) at (1,2.5) {13};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (b) at (3,2.5) {11};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (i) at (2,4.5) {24};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\end{scope}
|
|
\begin{scope}[shift={(-8,10)}]
|
|
\draw (-1,-1) rectangle (5,6);
|
|
\draw (0,0) grid (4,1);
|
|
\node[anchor=center,scale=0.8] at (0.5, 0.5) {15};
|
|
\node[anchor=center,scale=0.8] at (1.5, 0.5) {13};
|
|
\node[anchor=center,scale=0.8] at (2.5, 0.5) {6};
|
|
\node[anchor=center,scale=0.8] at (3.5, 0.5) {8};
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (a) at (1,2.5) {28};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (b) at (3,2.5) {14};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (i) at (2,4.5) {42};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\end{scope}
|
|
\begin{scope}[shift={(8,10)}]
|
|
\draw (-1,-1) rectangle (5,6);
|
|
\draw (0,0) grid (4,1);
|
|
\node[anchor=center,scale=0.8] at (0.5, 0.5) {11};
|
|
\node[anchor=center,scale=0.8] at (1.5, 0.5) {14};
|
|
\node[anchor=center,scale=0.8] at (2.5, 0.5) {10};
|
|
\node[anchor=center,scale=0.8] at (3.5, 0.5) {9};
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (a) at (1,2.5) {25};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (b) at (3,2.5) {19};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (i) at (2,4.5) {44};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\end{scope}
|
|
\begin{scope}[shift={(0,20)}]
|
|
\draw (-1,-1) rectangle (5,6);
|
|
\draw (0,0) grid (4,1);
|
|
\node[anchor=center,scale=0.8] at (0.5, 0.5) {26};
|
|
\node[anchor=center,scale=0.8] at (1.5, 0.5) {27};
|
|
\node[anchor=center,scale=0.8] at (2.5, 0.5) {16};
|
|
\node[anchor=center,scale=0.8] at (3.5, 0.5) {17};
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (a) at (1,2.5) {53};
|
|
\path[draw,thick,-] (a) -- (0.5,1);
|
|
\path[draw,thick,-] (a) -- (1.5,1);
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (b) at (3,2.5) {33};
|
|
\path[draw,thick,-] (b) -- (2.5,1);
|
|
\path[draw,thick,-] (b) -- (3.5,1);
|
|
|
|
\node[draw, circle,scale=0.8,inner sep=1pt] (i) at (2,4.5) {86};
|
|
\path[draw,thick,-] (i) -- (a);
|
|
\path[draw,thick,-] (i) -- (b);
|
|
\end{scope}
|
|
\path[draw,thick,-] (2,19) -- (-6,16);
|
|
\path[draw,thick,-] (2,19) -- (10,16);
|
|
\path[draw,thick,-] (-6,9) -- (-10,6);
|
|
\path[draw,thick,-] (-6,9) -- (-2,6);
|
|
\path[draw,thick,-] (10,9) -- (6,6);
|
|
\path[draw,thick,-] (10,9) -- (14,6);
|
|
\end{tikzpicture}
|
|
\end{center}
|
|
|
|
The operations in a two-dimensional segment tree
|
|
take $O(\log^2 n)$ time, because the big tree
|
|
and each small tree contain $O(\log n)$ levels.
|
|
The tree uses $O(n^2)$ memory, because each
|
|
small tree uses $O(n)$ memory.
|
|
|
|
Using a similar idea, it is also possible to create
|
|
segment trees with more dimensions,
|
|
but this is rarely needed.
|