cphb/luku28.tex

1176 lines
37 KiB
TeX
Raw Normal View History

2016-12-28 23:54:51 +01:00
\chapter{Segment trees revisited}
\index{segmenttipuu@segmenttipuu}
Segmenttipuu on tehokas tietorakenne,
joka mahdollistaa monenlaisten
kyselyiden toteuttamisen tehokkaasti.
Tähän mennessä olemme käyttäneet
kuitenkin segmenttipuuta melko rajoittuneesti.
Nyt on aika tutustua pintaa syvemmältä
segmenttipuun mahdollisuuksiin.
Tähän mennessä olemme kulkeneet segmenttipuuta
\textit{alhaalta ylöspäin} lehdistä juureen.
Vaihtoehtoinen tapa toteuttaa puun käsittely
on kulkea \textit{ylhäältä alaspäin} juuresta lehtiin.
Tämä kulkusuunta on usein kätevä silloin,
kun kyseessä on perustilannetta
monimutkaisempi segmenttipuu.
Esimerkiksi välin $[a,b]$ summan laskeminen
segmenttipuussa tapahtuu alhaalta ylöspäin
tuttuun tapaan näin (luku 9.3):
\begin{lstlisting}
int summa(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}
Ylhäältä alaspäin toteutettuna funktiosta tulee:
\begin{lstlisting}
int summa(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 summa(a, min(x+d-1,b), 2*k, x, x+d-1) +
summa(max(x+d,a), b, 2*k+1, x+d, y);
}
\end{lstlisting}
Nyt välin $[a,b]$ summan saa laskettua
kutsumalla funktiota näin:
\begin{lstlisting}
int s = summa(a, b, 1, 0, N-1);
\end{lstlisting}
Parametri $k$ ilmaisee kohdan
taulukossa \texttt{p}.
Aluksi $k$:n arvona on 1,
koska summan laskeminen alkaa
segmenttipuun juuresta.
Väli $[x,y]$ on parametria $k$ vastaava väli,
aluksi koko kyselyalue eli $[0,N-1]$.
Jos väli $[a,b]$ on välin $[x,y]$
ulkopuolella, välin summa on 0.
Jos taas välit $[a,b]$ ja $[x,y]$
ovat samat, summan saa taulukosta \texttt{p}.
Jos väli $[a,b]$ on kokonaan tai osittain välin $[x,y]$
sisällä, haku jatkuu rekursiivisesti
välin $[x,y]$ vasemmasta ja oikeasta puoliskosta.
Kummankin puoliskon koko on $d=\frac{1}{2}(y-x+1)$,
joten vasen puolisko kattaa välin $[x,x+d-1]$
ja oikea puolisko kattaa välin $[x+d,y]$.
Seuraava kuva näyttää,
kuinka haku etenee puussa,
kun lasketaan puun alle
merkityn välin summa.
Harmaat solmut ovat kohtia,
joissa rekursio päättyy ja välin
summan saa taulukosta \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}
Myös tässä toteutuksessa kyselyn aikavaativuus on $O(\log n)$,
koska haun aikana käsiteltävien solmujen määrä on $O(\log n)$.
\section{Laiska eteneminen}
\index{laiska eteneminen@laiska eteneminen}
\index{laiska segmenttipuu@laiska segmenttipuu}
\key{Laiska eteneminen}
mahdollistaa segmenttipuun,
jossa voi sekä muuttaa väliä että kysyä tietoa väliltä
ajassa $O(\log n)$.
Ideana on suorittaa muutokset ja kyselyt ylhäältä
alaspäin ja toteuttaa muutokset laiskasti niin,
että ne välitetään puussa alaspäin vain silloin,
kun se on välttämätöntä.
Laiskassa segmenttipuussa solmuihin liittyy
kahdenlaista tietoa.
Kuten tavallisessa segmenttipuussa,
jokaisessa solmussa on sitä vastaavan välin
summa tai muu haluttu tieto.
Tämän lisäksi solmussa voi olla laiskaan etenemiseen
liittyvää tietoa, jota ei ole vielä välitetty
solmusta alaspäin.
Välin muutostapa voi olla joko
\textit{lisäys} tai \textit{asetus}.
Lisäyksessä välin jokaiseen alkioon lisätään
tietty arvo, ja asetuksessa välin
jokainen alkio saa tietyn arvon.
Kummankin operaation toteutus on melko samanlainen,
ja puu voi myös sallia samaan aikaan
molemmat muutostavat.
\subsubsection{Laiska segmenttipuu}
Tarkastellaan esimerkkinä tilannetta,
jossa segmenttipuun
tulee toteuttaa seuraavat operaatiot:
\begin{itemize}
\item lisää jokaisen välin $[a,b]$ alkioon arvo $u$
\item laske välin $[a,b]$ alkioiden summa
\end{itemize}
Toteutamme puun, jonka jokaisessa
solmussa on kaksi arvoa $s/z$:
välin lukujen summa $s$,
kuten tavallisessa segmenttipuussa, sekä
laiska muutos $z$,
joka tarkoittaa,
että kaikkiin välin lukuihin tulee lisätä $z$.
Seuraavassa puussa jokaisessa solmussa $z=0$
eli mitään muutoksia ei ole kesken.
\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}
Kun välin $[a,b]$ solmuja kasvatetaan $u$:lla,
alkaa kulku puun juuresta lehtiä kohti.
Kulun aikana tapahtuu kahdenlaisia muutoksia puun solmuihin:
Jos solmun väli $[x,y]$ kuuluu kokonaan
muutettavalle välille $[a,b]$,
solmun $z$-arvo kasvaa $u$:llä ja kulku pysähtyy.
Jos taas väli $[x,y]$ kuuluu osittain välille $[a,b]$,
solmun $s$-arvo kasvaa $hu$:llä,
missä $h$ on välien $[a,b]$ ja $[x,y]$ yhteisen osan pituus,
ja kulku jatkuu rekursiivisesti alaspäin.
Kasvatetaan esimerkiksi puun alle merkittyä väliä 2:lla:
\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}
Välin $[a,b]$ summan laskenta tapahtuu myös
kulkuna puun juuresta lehtiä kohti.
Jos solmun väli $[x,y]$ kuuluu kokonaan väliin $[a,b]$,
kyselyn summaan lisätään solmun $s$-arvo
sekä mahdollinen $z$-arvon tuottama lisäys.
Muussa tapauksessa kulku jatkuu rekursiivisesti alaspäin solmun lapsiin.
Aina ennen solmun käsittelyä siinä mahdollisesti
oleva laiska muutos välitetään tasoa alemmas.
Tämä tapahtuu sekä välin muutoskyselyssä
että summakyselyssä.
Ideana on, että laiska muutos etenee alaspäin
vain silloin, kun tämä on välttämätöntä,
jotta puun käsittely on tehokasta.
Seuraava kuva näyttää, kuinka äskeinen puu muuttuu,
kun siitä lasketaan puun alle merkityn välin summa:
\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}
Tämän kyselyn seurauksena laiska muutos eteni alaspäin
laatikolla ympäröidyssä puun osassa.
Laiskaa muutosta täytyi viedä alaspäin, koska kyselyn
kohteena oleva väli osui osittain laiskan muutoksen välille.
Huomaa, että joskus puussa olevia laiskoja muutoksia täytyy yhdistää.
Näin tapahtuu silloin, kun solmussa on valmiina laiska muutos
ja siihen tulee ylhäältä toinen laiska muutos.
Tässä tapauksessa yhdistäminen on helppoa,
koska muutokset $z_1$ ja $z_2$ aiheuttavat yhdessä muutoksen $z_1+z_2$.
\subsubsection{Polynomimuutos}
Laiskaa segmenttipuuta voi yleistää niin,
että väliä muuttaa polynomi
\[p(u) = t_k u^k + t_{k-1} u^{k-1} + \cdots + t_0.\]
Ideana on, että välin ensimmäisen kohdan
muutos on $p(0)$, toisen kohdan muutos on $p(1)$ jne.,
eli välin $[a,b]$ kohdan $i$ muutos on $p(i-a)$.
Esimerkiksi polynomin $p(u)=u+1$ lisäys välille
$[a,b]$ tarkoittaa, että kohta $a$ kasvaa 1:llä,
kohta $a+1$ kasvaa 2:lla, kohta $a+2$ kasvaa 3:lla jne.
Polynomimuutoksen voi toteuttaa niin,
että jokaisessa solmussa on $k+2$ arvoa,
missä $k$ on polynomin asteluku.
Arvo $s$ kertoo solmua vastaavan välin summan kuten ennenkin,
ja arvot $z_0,z_1,\ldots,z_k$ ovat polynomin kertoimet,
joka ilmaisee väliin kohdistuvan laiskan muutoksen.
Nyt välin $[x,y]$ summa on
\[s+\sum_{u=0}^{y-x} z_k u^k + z_{k-1} u^{k-1} + \cdots + z_0,\]
jonka saa laskettua tehokkaasti osissa summakaavoilla.
Esimerkiksi termin $z_0$ summaksi tulee
$(y-x+1)z_0$ ja termin $z_1 u$ summaksi tulee
\[z_1(0+1+\cdots+y-x) = z_1 \frac{(y-x)(y-x+1)}{2} .\]
Kun muutos etenee alaspäin puussa,
polynomin $p(u)$ indeksointi muuttuu,
koska jokaisella välillä $[x,y]$
polynomin arvot tulevat kohdista $x=0,1,\ldots,y-x$.
Tämä ei kuitenkaan tuota ongelmia,
koska $p'(u)=p(u+h)$ on aina
samanasteinen polynomi kuin $p(u)$.
Esimerkiksi jos $p(u)=t_2 u^2+t_1 u-t_0$, niin
\[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{Dynaaminen toteutus}
\index{dynaaminen segmenttipuu@dynaaminen segmenttipuu}
Tavallinen segmenttipuu on staattinen,
eli jokaiselle solmulle on paikka taulukossa
ja puu vie kiinteän määrän muistia.
Tämä toteutus kuitenkin tuhlaa muistia,
jos suurin osa puun solmuista on tyhjiä.
\key{Dynaaminen segmenttipuu} varaa muistia vain
niille solmuille, joita todella tarvitaan.
Solmut on kätevää tallentaa tietueina tähän tapaan:
\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}
Tässä $s$ on solmussa oleva arvo,
$[x,y]$ on solmua vastaava väli
ja $l$ ja $r$ osoittavat
solmun vasempaan ja oikeaan alipuuhun.
Tämän jälkeen solmuja voi käsitellä seuraavasti:
\begin{lstlisting}
// uuden solmun luonti
node *u = new node(0, 0, 15);
// kentän muuttaminen
u->s = 5;
\end{lstlisting}
\subsubsection{Harva segmenttipuu}
\index{harva segmenttipuu@harva segmenttipuu}
Dynaaminen segmenttipuu on hyödyllinen,
jos puun indeksialue $[0,N-1]$ on \textit{harva}
eli $N$ on suuri mutta vain
pieni osa indekseistä on käytössä.
Siinä missä tavallinen segmenttipuu
vie muistia $O(N)$,
dynaaminen segmenttipuu vie muistia
vain $O(n \log N)$, missä $n$ on
käytössä olevien indeksien määrä.
\key{Harva segmenttipuu} aluksi tyhjä
ja sen ainoa solmu on $[0,N-1]$.
Kun puu muuttuu, siihen lisätään
solmuja dynaamisesti sitä mukaa kuin niitä tarvitaan
uusien indeksien vuoksi.
Esimerkiksi jos $N=16$ ja indeksejä
3 ja 10 on muutettu,
puu sisältää seuraavat solmut:
\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}
Reitti puun juuresta lehteen sisältää
$O(\log N)$ solmua,
joten jokainen muutos puuhun lisää
enintään $O(\log N)$ uutta solmua puuhun.
Niinpä $n$ muutoksen jälkeen puussa
on enintään $O(n \log N)$ solmua.
Huomaa, että jos kaikki tarvittavat indeksit
ovat tiedossa
algoritmin alussa, dynaamisen segmenttipuun
sijasta voi käyttää tavallista segmenttipuuta
ja indeksien pakkausta (luku 9.4).
Tämä ei ole kuitenkaan mahdollista,
jos indeksit syntyvät vasta algoritmin aikana.
\subsubsection{Persistentti segmenttipuu}
\index{persistentti segmenttipuu@persistentti segmenttipuu}
\index{muutoshistoria@muutoshistoria}
Dynaamisen toteutuksen avulla on myös
mahdollista luoda \key{persistentti segmenttipuu},
joka säilyttää puun muutoshistorian.
Tällöin muistissa on jokainen
segmenttipuun vaihe, joka on esiintynyt
algoritmin suorituksen aikana.
Muutoshistorian hyötynä on,
että kaikkia vanhoja puita voi käsitellä
segmenttipuun tapaan,
koska niiden rakenne on edelleen olemassa.
Vanhoista puista voi myös johtaa uusia
puita, joita voi muokata edelleen.
Tarkastellaan esimerkiksi seuraavaa muutossarjaa,
jossa punaiset solmut muuttuvat päivityksessä
ja muut solmut säilyvät ennallaan:
\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) {vaihe 1};
\node at (3+5,-3) {vaihe 2};
\node at (3+10,-3) {vaihe 3};
\end{tikzpicture}
\end{center}
Jokaisen muutoksen jälkeen suurin osa puun
solmuista säilyy ennallaan,
joten muistia säästävä tapa tallentaa muutoshistoria
on käyttää mahdollisimman paljon hyväksi
puun vanhoja osia muutoksissa.
Tässä tapauksessa muutoshistorian voi
tallentaa seuraavasti:
\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) {vaihe 1};
\node at (3+5,-3) {vaihe 2};
\node at (3+10,-3) {vaihe 3};
\end{tikzpicture}
\end{center}
Nyt muistissa on jokaisesta puun vaiheesta
puun juuri, jonka avulla pystyy selvittämään
koko puun rakenteen kyseisellä hetkellä.
Jokainen muutos tuo vain $O(\log N)$ uutta solmua puuhun,
kun puun indeksialue on $[0,N-1]$,
joten koko muutoshistorian pitäminen muistissa on mahdollista.
\section{Tietorakenteet}
Segmenttipuun solmussa voi olla
yksittäisen arvon
sijasta myös jokin tietorakenne,
joka pitää yllä tietoa solmua vastaavasta välistä.
Tällöin segmenttipuun operaatiot vievät aikaa
$O(f(n) \log n)$, missä $f(n)$ on
yksittäisen solmun tietorakenteen
käsittelyyn kuluva aika.
Tarkastellaan esimerkkinä segmenttipuuta,
jonka avulla voi laskea, montako kertaa
luku $x$ esiintyy taulukon välillä $[a,b]$.
Esimerkiksi seuraavassa taulukossa
luku 1 esiintyy kolme kertaa
merkityllä välillä:
\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}
Ideana on toteuttaa segmenttipuu, jonka
jokaisessa solmussa on tietorakenne,
josta voi kysyä,
montako kertaa luku $x$ esiintyy solmun välillä.
Tällaisen segmenttipuun avulla
vastaus kyselyyn syntyy laskemalla yhteen
esiintymismäärät väleiltä, joista $[a,b]$ muodostuu.
Esimerkiksi yllä olevasta taulukosta syntyy
seuraava segmenttipuu:
\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}
Sopiva tietorakenne segmenttipuun toteuttamiseen on
hakemistorakenne, joka pitää kirjaa välillä esiintyvien
lukujen määrästä.
Esimerkiksi \texttt{map}-ra\-ken\-net\-ta käyttäen
yhden solmun käsittely vie aikaa $O(\log n)$,
minkä seurauksena kyselyn aikavaativuus on $O(\log^2 n)$.
Solmuissa olevat tietorakenteet kasvattavat
segmenttipuun muistinkäyttöä.
Tässä tapauksessa
segmenttipuu vie tilaa $O(n \log n)$,
koska siinä on $O(\log n)$ tasoa, joista
jokaisella hakemistorakenteet sisältävät $O(n)$ lukua.
\section{Kaksiulotteisuus}
\index{kaksiulotteinen segmenttipuu@kaksiulotteinen segmenttipuu}
\key{Kaksiulotteinen segmenttipuu} mahdollistaa
kaksiulotteisen taulukon
suorakulmaisia alueita koskevat kyselyt.
Tällaisen segmenttipuun voi toteuttaa
sisäkkäisinä segmenttipuina:
suuri puu vastaa taulukon rivejä
ja sen kussakin solmussa on pieni puu,
joka vastaa taulukon sarakkeita.
Esimerkiksi taulukon
\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}
alueiden summia voi laskea seuraavasta segmenttipuusta:
\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}
Kaksiulotteisen
segmenttipuun operaatiot vievät aikaa
$O(\log^2 n)$,
koska suuressa puussa ja kussakin
pienessä puussa on $O(\log n)$ tasoa.
Segmenttipuu vie muistia $O(n^2)$,
koska jokainen pieni puu
vie muistia $O(n)$.
Vastaavalla tavalla voi luoda myös segmenttipuita,
joissa on vielä enemmän ulottuvuuksia,
mutta tälle on harvoin tarvetta.