Segmentno stablo

Lekcija 11 od 11 · Strukture podataka

Segmentno stablo deli niz na intervale (segmente) i za svaki pamti rezultat – zbir, minimum, maksimum ili NZD. Upit za bilo koji interval i izmena jednog elementa traju O(log n).

Pre nego što počneš: potrebno predznanje – Fenwick stablo, Uvod u rekurziju.
Kako da učiš: svaki primer prekucaj i pokreni, a zadatke na kraju prvo reši sam/a; uputstvo i rešenje otvori tek posle toga. Svi programi su u C++-u.

Ideja

Koren stabla odgovara celom nizu [0, n−1]. Svaki čvor koji pokriva [l, r] ima dva deteta: [l, m] i [m+1, r], gde je m = (l+r)/2. Listovi su pojedinačni elementi. U svakom čvoru čuvamo rezultat za njegov interval – za minimum: t[čvor] = min(t[levo], t[desno]).

Čvorove čuvamo u nizu kao kod hipa: koren je 1, deca čvora v su 2v i 2v+1. Niz dužine 4n je uvek dovoljan.

  • Upit [ql, qr]: ako je interval čvora potpuno unutar upita – vrati vrednost čvora; ako je potpuno van – vrati neutralnu vrednost (za minimum: beskonačno); inače pitaj oba deteta.
  • Izmena pozicije i: spusti se do lista, promeni ga, i na povratku ponovo izračunaj sve pretke.

Kod: minimum na intervalu uz izmene

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int n;
vector<int> a, t;

void izgradi(int v, int l, int r) {
    if (l == r) { t[v] = a[l]; return; }
    int m = (l + r) / 2;
    izgradi(2 * v, l, m);
    izgradi(2 * v + 1, m + 1, r);
    t[v] = min(t[2 * v], t[2 * v + 1]);
}

int upit(int v, int l, int r, int ql, int qr) {
    if (qr < l || r < ql) return INT_MAX;          // potpuno van upita
    if (ql <= l && r <= qr) return t[v];           // potpuno unutar upita
    int m = (l + r) / 2;
    return min(upit(2 * v, l, m, ql, qr), upit(2 * v + 1, m + 1, r, ql, qr));
}

void izmeni(int v, int l, int r, int i, int x) {
    if (l == r) { t[v] = x; return; }
    int m = (l + r) / 2;
    if (i <= m) izmeni(2 * v, l, m, i, x);
    else izmeni(2 * v + 1, m + 1, r, i, x);
    t[v] = min(t[2 * v], t[2 * v + 1]);           // ponovo izračunaj roditelja
}

int main() {
    int q;
    cin >> n >> q;
    a.resize(n);
    t.assign(4 * n, 0);
    for (int &x : a) cin >> x;
    izgradi(1, 0, n - 1);
    while (q--) {
        int tip, x, y;
        cin >> tip >> x >> y;
        if (tip == 1) izmeni(1, 0, n - 1, x - 1, y);              // a[x] = y
        else cout << upit(1, 0, n - 1, x - 1, y - 1) << "\n";      // min a[x..y]
    }
    return 0;
}

Ulaz i izlaz koriste pozicije od 1, a stablo radi sa pozicijama od 0 – zato x - 1.

Druge operacije i lenja propagacija

Za zbir umesto min piši + i vrati 0 za interval van upita; za maksimum max i INT_MIN; za NZD gcd i 0. Kada izmena ne menja jedan element nego ceo interval (npr. „dodaj 5 na pozicije 3–10“), koristi se lenja propagacija: izmena se zapiše u čvor i spušta deci tek kada su potrebna. Detaljnije: CP-Algorithms – Segment Tree.

Zadaci za vežbu

Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno tačna na primerima iz teksta.

ZADATAK 01Težina: Srednje teško

Zbir na intervalu

Prepravi segmentno stablo tako da odgovara na upit „zbir na intervalu [l, r]“ i podržava izmenu „a[i] = v“. Format ulaza je isti kao u primeru iz lekcije.

Primer

Ulaz

5 4
1 2 3 4 5
2 1 5
1 3 10
2 2 4
2 3 3

Izlaz

15
16
10
ZADATAK 02Težina: Srednje teško

Najviša zgrada u delu ulice

U ulici je n zgrada datih visina. Upiti: D i h – na zgradu i dograđuje se h metara; M l r – kolika je najveća visina zgrade od l-te do r-te?

Primer

Ulaz

5 4
10 30 20 40 15
M 1 3
D 3 15
M 1 3
M 4 5

Izlaz

30
35
40
Česte greške i saveti
  • Niz za stablo neka ima 4n elemenata.
  • Neutralna vrednost mora odgovarati operaciji: 0 za zbir, beskonačno za minimum, minus beskonačno za maksimum.
  • Posle izmene obavezno ponovo izračunaj roditelje na putu do korena.
  • Ako postoje samo upiti zbira bez izmena, dovoljni su prefiksni zbirovi; ako postoje izmene i samo zbir – Fenwick je kraći.

Proveri znanje

Otvori kviz

Mini kviz: segmentno stablo

1. Koja su deca čvora 5 u nizovskom zapisu stabla?




2. Šta upit vraća za čvor čiji je interval potpuno van upita, kod minimuma?




3. Kolika je složenost upita na intervalu?