Chapter 28 first version
This commit is contained in:
parent
4994a68057
commit
1f0c8e66af
289
luku28.tex
289
luku28.tex
|
@ -538,19 +538,21 @@ of equal degree as $p(u)$.
|
||||||
For example, if $p(u)=t_2 u^2+t_1 u-t_0$, then
|
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.\]
|
\[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}
|
\section{Dynamic trees}
|
||||||
|
|
||||||
\index{dynaaminen segmenttipuu@dynaaminen segmenttipuu}
|
\index{dynamic segment tree}
|
||||||
|
|
||||||
Tavallinen segmenttipuu on staattinen,
|
A regular segment tree is static,
|
||||||
eli jokaiselle solmulle on paikka taulukossa
|
which means that each node has a fixed position
|
||||||
ja puu vie kiinteän määrän muistia.
|
in the array and storing the tree requires
|
||||||
Tämä toteutus kuitenkin tuhlaa muistia,
|
a fixed amount of memory.
|
||||||
jos suurin osa puun solmuista on tyhjiä.
|
However, if most nodes are empty, such an
|
||||||
\key{Dynaaminen segmenttipuu} varaa muistia vain
|
implementation wastes memory.
|
||||||
niille solmuille, joita todella tarvitaan.
|
In a \key{dynamic segment tree},
|
||||||
|
memory is reserved only for nodes that
|
||||||
|
are actually needed.
|
||||||
|
|
||||||
Solmut on kätevää tallentaa tietueina tähän tapaan:
|
The nodes can be represented as structs as follows:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
struct node {
|
struct node {
|
||||||
|
@ -560,42 +562,39 @@ struct node {
|
||||||
node(int x, int a, int b) : s(s), x(x), y(y) {}
|
node(int x, int a, int b) : s(s), x(x), y(y) {}
|
||||||
};
|
};
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Tässä $s$ on solmussa oleva arvo,
|
Here $s$ is the value of the node,
|
||||||
$[x,y]$ on solmua vastaava väli
|
$[x,y]$ is the corresponding range,
|
||||||
ja $l$ ja $r$ osoittavat
|
and $l$ and $r$ point to the left
|
||||||
solmun vasempaan ja oikeaan alipuuhun.
|
and right subtree.
|
||||||
|
|
||||||
Tämän jälkeen solmuja voi käsitellä seuraavasti:
|
After this, nodes can be manipulated as follows:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
// uuden solmun luonti
|
// create new node
|
||||||
node *u = new node(0, 0, 15);
|
node *u = new node(0, 0, 15);
|
||||||
// kentän muuttaminen
|
// change value
|
||||||
u->s = 5;
|
u->s = 5;
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
\subsubsection{Harva segmenttipuu}
|
\subsubsection{Sparse segment tree}
|
||||||
|
|
||||||
\index{harva segmenttipuu@harva segmenttipuu}
|
\index{sparse segment tree}
|
||||||
|
|
||||||
Dynaaminen segmenttipuu on hyödyllinen,
|
A dynamic segment tree is useful if
|
||||||
jos puun indeksialue $[0,N-1]$ on \textit{harva}
|
the range $[0,N-1]$ covered by the tree is \emph{sparse},
|
||||||
eli $N$ on suuri mutta vain
|
which means that $N$ is large but only a
|
||||||
pieni osa indekseistä on käytössä.
|
small portion of the indices are used.
|
||||||
Siinä missä tavallinen segmenttipuu
|
While a regular segment tree uses $O(n)$ memory,
|
||||||
vie muistia $O(N)$,
|
a dynamic segment tree only uses $O(n \log N)$ memory,
|
||||||
dynaaminen segmenttipuu vie muistia
|
where $n$ is the number of indices used.
|
||||||
vain $O(n \log N)$, missä $n$ on
|
|
||||||
käytössä olevien indeksien määrä.
|
|
||||||
|
|
||||||
\key{Harva segmenttipuu} aluksi tyhjä
|
A \key{sparse segment tree} is initially empty
|
||||||
ja sen ainoa solmu on $[0,N-1]$.
|
and its only node is $[0,N-1]$.
|
||||||
Kun puu muuttuu, siihen lisätään
|
When the tree changes, new nodes are added dynamically
|
||||||
solmuja dynaamisesti sitä mukaa kuin niitä tarvitaan
|
always when they are needed because of new indices.
|
||||||
uusien indeksien vuoksi.
|
For example, if $N=16$, and the elements
|
||||||
Esimerkiksi jos $N=16$ ja indeksejä
|
in indices 3 and 10 have been changes,
|
||||||
3 ja 10 on muutettu,
|
the tree contains the following nodes:
|
||||||
puu sisältää seuraavat solmut:
|
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tikzpicture}[scale=0.9]
|
\begin{tikzpicture}[scale=0.9]
|
||||||
\scriptsize
|
\scriptsize
|
||||||
|
@ -621,43 +620,45 @@ puu sisältää seuraavat solmut:
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
Reitti puun juuresta lehteen sisältää
|
Any path from the root to a leaf contains
|
||||||
$O(\log N)$ solmua,
|
$O(\log N)$ nodes,
|
||||||
joten jokainen muutos puuhun lisää
|
so each change adds at most $O(\log n)$
|
||||||
enintään $O(\log N)$ uutta solmua puuhun.
|
new nodes to the tree.
|
||||||
Niinpä $n$ muutoksen jälkeen puussa
|
Thus, after $n$ changes, the tree contains
|
||||||
on enintään $O(n \log N)$ solmua.
|
at most $O(n \log N)$ nodes.
|
||||||
|
|
||||||
Huomaa, että jos kaikki tarvittavat indeksit
|
Note that if all indices of the elements
|
||||||
ovat tiedossa
|
are known at the beginning of the algorithm,
|
||||||
algoritmin alussa, dynaamisen segmenttipuun
|
a dynamic segment tree is not needed,
|
||||||
sijasta voi käyttää tavallista segmenttipuuta
|
but we can use a regular segment tree with
|
||||||
ja indeksien pakkausta (luku 9.4).
|
index compression (Chapter 9.4).
|
||||||
Tämä ei ole kuitenkaan mahdollista,
|
However, this is not possible if the indices
|
||||||
jos indeksit syntyvät vasta algoritmin aikana.
|
are generated during the algorithm.
|
||||||
|
|
||||||
\subsubsection{Persistentti segmenttipuu}
|
\subsubsection{Persistent segment tree}
|
||||||
|
|
||||||
\index{persistentti segmenttipuu@persistentti segmenttipuu}
|
\index{persistent segment tree}
|
||||||
\index{muutoshistoria@muutoshistoria}
|
\index{version history}
|
||||||
|
|
||||||
Dynaamisen toteutuksen avulla on myös
|
Using a dynamic implementation,
|
||||||
mahdollista luoda \key{persistentti segmenttipuu},
|
it is also possible to create a
|
||||||
joka säilyttää puun muutoshistorian.
|
\key{persistent segment tree} that stores
|
||||||
Tällöin muistissa on jokainen
|
the \key{version history} of the tree.
|
||||||
segmenttipuun vaihe, joka on esiintynyt
|
In such an implementation, we can
|
||||||
algoritmin suorituksen aikana.
|
efficiently access
|
||||||
|
all versions of the tree that have been
|
||||||
|
existed during the algorithm.
|
||||||
|
|
||||||
Muutoshistorian hyötynä on,
|
When the version history is available,
|
||||||
että kaikkia vanhoja puita voi käsitellä
|
we can access all versions of the tree
|
||||||
segmenttipuun tapaan,
|
like a regular segment tree, because their
|
||||||
koska niiden rakenne on edelleen olemassa.
|
structure is stored.
|
||||||
Vanhoista puista voi myös johtaa uusia
|
We can also derive new trees from the history
|
||||||
puita, joita voi muokata edelleen.
|
and further manipulate them.
|
||||||
|
|
||||||
Tarkastellaan esimerkiksi seuraavaa muutossarjaa,
|
Consider the following sequence of updates,
|
||||||
jossa punaiset solmut muuttuvat päivityksessä
|
where red nodes change in an update
|
||||||
ja muut solmut säilyvät ennallaan:
|
and other nodes remain the same:
|
||||||
|
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tikzpicture}[scale=0.8]
|
\begin{tikzpicture}[scale=0.8]
|
||||||
|
@ -703,18 +704,18 @@ ja muut solmut säilyvät ennallaan:
|
||||||
\path[draw,thick,->] (3c) -- (6c);
|
\path[draw,thick,->] (3c) -- (6c);
|
||||||
\path[draw,thick,->] (3c) -- (7c);
|
\path[draw,thick,->] (3c) -- (7c);
|
||||||
|
|
||||||
\node at (3,-3) {vaihe 1};
|
\node at (3,-3) {step 1};
|
||||||
\node at (3+5,-3) {vaihe 2};
|
\node at (3+5,-3) {step 2};
|
||||||
\node at (3+10,-3) {vaihe 3};
|
\node at (3+10,-3) {step 3};
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
Jokaisen muutoksen jälkeen suurin osa puun
|
After each update, most nodes in the tree
|
||||||
solmuista säilyy ennallaan,
|
remain the same,
|
||||||
joten muistia säästävä tapa tallentaa muutoshistoria
|
so an efficient way to store the version history
|
||||||
on käyttää mahdollisimman paljon hyväksi
|
is to represent each tree in the history as a combination
|
||||||
puun vanhoja osia muutoksissa.
|
of new nodes and subtrees of previous trees.
|
||||||
Tässä tapauksessa muutoshistorian voi
|
In this case, the version history can be
|
||||||
tallentaa seuraavasti:
|
stored as follows:
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tikzpicture}[scale=0.8]
|
\begin{tikzpicture}[scale=0.8]
|
||||||
\path[use as bounding box] (0, 1) rectangle (16, -3.5);
|
\path[use as bounding box] (0, 1) rectangle (16, -3.5);
|
||||||
|
@ -755,36 +756,35 @@ tallentaa seuraavasti:
|
||||||
|
|
||||||
\path[draw,thick,->] (3c) -- (7c);
|
\path[draw,thick,->] (3c) -- (7c);
|
||||||
|
|
||||||
\node at (3,-3) {vaihe 1};
|
\node at (3,-3) {step 1};
|
||||||
\node at (3+5,-3) {vaihe 2};
|
\node at (3+5,-3) {step 2};
|
||||||
\node at (3+10,-3) {vaihe 3};
|
\node at (3+10,-3) {step 3};
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
Nyt muistissa on jokaisesta puun vaiheesta
|
The structure of each version of the tree in the history can be
|
||||||
puun juuri, jonka avulla pystyy selvittämään
|
reconstructed by following the pointers from the root.
|
||||||
koko puun rakenteen kyseisellä hetkellä.
|
Each update only adds $O(\log N)$ new nodes to the tree
|
||||||
Jokainen muutos tuo vain $O(\log N)$ uutta solmua puuhun,
|
when the indices are $[0,N-1]$,
|
||||||
kun puun indeksialue on $[0,N-1]$,
|
so it is possible to store the full version history
|
||||||
joten koko muutoshistorian pitäminen muistissa on mahdollista.
|
of the tree.
|
||||||
|
|
||||||
\section{Tietorakenteet}
|
\section{Data structures}
|
||||||
|
|
||||||
Segmenttipuun solmussa voi olla
|
Insted of a single value, a node in a segment tree
|
||||||
yksittäisen arvon
|
can also contain a data structure that maintains information
|
||||||
sijasta myös jokin tietorakenne,
|
about the corresponding range.
|
||||||
joka pitää yllä tietoa solmua vastaavasta välistä.
|
In this case, the operations of the tree take
|
||||||
Tällöin segmenttipuun operaatiot vievät aikaa
|
$O(f(n) \log n)$ time, where $f(n)$ is
|
||||||
$O(f(n) \log n)$, missä $f(n)$ on
|
the time needed for retrieving or updating the
|
||||||
yksittäisen solmun tietorakenteen
|
information in a single node.
|
||||||
käsittelyyn kuluva aika.
|
|
||||||
|
|
||||||
Tarkastellaan esimerkkinä segmenttipuuta,
|
As an example, consider a segment tree that
|
||||||
jonka avulla voi laskea, montako kertaa
|
supports queries of the form
|
||||||
luku $x$ esiintyy taulukon välillä $[a,b]$.
|
''how many times does element $x$ appear
|
||||||
Esimerkiksi seuraavassa taulukossa
|
in range $[a,b]$?''
|
||||||
luku 1 esiintyy kolme kertaa
|
For example, element 1 appears three times
|
||||||
merkityllä välillä:
|
in the following subarray:
|
||||||
|
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tikzpicture}[scale=0.7]
|
\begin{tikzpicture}[scale=0.7]
|
||||||
|
@ -802,16 +802,17 @@ merkityllä välillä:
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
Ideana on toteuttaa segmenttipuu, jonka
|
The idea is to construct a segment tree
|
||||||
jokaisessa solmussa on tietorakenne,
|
where each node has a data structure
|
||||||
josta voi kysyä,
|
that can return the number of any element $x$
|
||||||
montako kertaa luku $x$ esiintyy solmun välillä.
|
in the range.
|
||||||
Tällaisen segmenttipuun avulla
|
Using such a segment tree,
|
||||||
vastaus kyselyyn syntyy laskemalla yhteen
|
the answer for a query can be calculated
|
||||||
esiintymismäärät väleiltä, joista $[a,b]$ muodostuu.
|
by combining the results from the nodes
|
||||||
|
that belong to the range.
|
||||||
|
|
||||||
Esimerkiksi yllä olevasta taulukosta syntyy
|
For example, the following segment tree
|
||||||
seuraava segmenttipuu:
|
corresponds to the above array:
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tikzpicture}[scale=0.7]
|
\begin{tikzpicture}[scale=0.7]
|
||||||
|
|
||||||
|
@ -955,35 +956,32 @@ seuraava segmenttipuu:
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\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)$.
|
||||||
|
|
||||||
Sopiva tietorakenne segmenttipuun toteuttamiseen on
|
Data structures in nodes increase the memory usage
|
||||||
hakemistorakenne, joka pitää kirjaa välillä esiintyvien
|
of the tree.
|
||||||
lukujen määrästä.
|
In this example, $O(n \log n)$ memory is needed,
|
||||||
Esimerkiksi \texttt{map}-ra\-ken\-net\-ta käyttäen
|
because the tree consists of $O(\log n)$ levels,
|
||||||
yhden solmun käsittely vie aikaa $O(\log n)$,
|
and the map structures contain a total
|
||||||
minkä seurauksena kyselyn aikavaativuus on $O(\log^2 n)$.
|
of $O(n)$ values at each level.
|
||||||
|
|
||||||
Solmuissa olevat tietorakenteet kasvattavat
|
\section{Two-dimensionality}
|
||||||
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{two-dimensional segment tree}
|
||||||
|
|
||||||
\index{kaksiulotteinen segmenttipuu@kaksiulotteinen segmenttipuu}
|
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.
|
||||||
|
|
||||||
\key{Kaksiulotteinen segmenttipuu} mahdollistaa
|
For example, in the array
|
||||||
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{center}
|
||||||
\begin{tikzpicture}[scale=0.7]
|
\begin{tikzpicture}[scale=0.7]
|
||||||
\draw (0,0) grid (4,4);
|
\draw (0,0) grid (4,4);
|
||||||
|
@ -1009,7 +1007,8 @@ Esimerkiksi taulukon
|
||||||
\node[anchor=center] at (3.5, 3.5) {6};
|
\node[anchor=center] at (3.5, 3.5) {6};
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
alueiden summia voi laskea seuraavasta segmenttipuusta:
|
sums of rectangles can be calculated
|
||||||
|
from the following segment tree:
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tikzpicture}[scale=0.4]
|
\begin{tikzpicture}[scale=0.4]
|
||||||
\footnotesize
|
\footnotesize
|
||||||
|
@ -1155,16 +1154,12 @@ alueiden summia voi laskea seuraavasta segmenttipuusta:
|
||||||
\end{tikzpicture}
|
\end{tikzpicture}
|
||||||
\end{center}
|
\end{center}
|
||||||
|
|
||||||
Kaksiulotteisen
|
The operations in a two-dimensional segment tree
|
||||||
segmenttipuun operaatiot vievät aikaa
|
take $O(\log^2 n)$ time, because the big tree
|
||||||
$O(\log^2 n)$,
|
and each small tree contain $O(\log n)$ levels.
|
||||||
koska suuressa puussa ja kussakin
|
The tree uses $O(n^2)$ memory, because each
|
||||||
pienessä puussa on $O(\log n)$ tasoa.
|
small tree uses $O(n)$ memory.
|
||||||
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.
|
|
||||||
|
|
||||||
|
Using a similar idea, it is also possible to create
|
||||||
|
segment trees with more dimensions,
|
||||||
|
but this is rarely needed.
|
||||||
|
|
Loading…
Reference in New Issue