\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.