| title | Segment Tree | ||
|---|---|---|---|
| tags |
|
Segment Tree bir dizide
Segment Tree, Fenwick Tree ve Sparse Table yapılarından farklı olarak elemanlar üzerinde güncelleme yapılabilmesi ve minimum, maksimum gibi sorgulara da olanak sağlaması yönünden daha kullanışlıdır. Ayrıca Segment Tree
Segment Tree, "Complete Binary Tree" yapısına sahiptir. Segment Tree'nin yaprak düğümlerinde dizinin elemanları saklıdır ve bu düğümlerin atası olan her düğüm kendi çocuğu olan düğümlerinin cevaplarının birleşmesiyle oluşur. Bu sayede her düğümde belirli aralıkların cevapları ve root düğümünde tüm dizinin cevabı saklanır. Örneğin toplam sorgusu için kurulmuş bir Segment Tree yapısı için her düğümün değeri çocuklarının değerleri toplamına eşittir.
![a = [41,67,6,30,85,43,39] dizisinde toplam sorgusu icin oluşturulmuş Segment Tree yapısı](img/segtree.png){ width="100%" } $a = [41,67,6,30,85,43,39]$ dizisinde toplam sorgusu icin oluşturulmuş Segment Tree yapısıvoid build(int ind, int l, int r) {
// tree[ind] dizinin [l,r] araliginin cevabini saklar.
if (l == r) { // yaprak dugum'e ulasti
tree[ind] = a[l]; // bu dugum dizinin l. elamaninin cevabini saklar
} else {
int mid = (l + r) / 2;
build(ind * 2, l, mid);
build(ind * 2 + 1, mid + 1, r);
// [l,r] araliginin cevabini
// [l,mid] ve [mid + 1,r] araliklarinin cevaplarinin birlesmesiyle olusur.
tree[ind] = tree[ind * 2] + tree[ind * 2 + 1];
}
}Herhangi bir
-
$[l,r]$ aralığını ağacımızda cevapları saklı olan en geniş aralıklara parçala. - Bu aralıkların cevaplarını birleştirerek istenilen cevabı hesapla.
Ağacın her derinliğinde cevabımız için gerekli aralıklardan maksimum
// [lw,rw] sorguda cevabini aradigimiz aralik.
// [l,r] ise agactaki ind nolu node'da cevabini sakladigimiz aralik.
int query(int ind, int l, int r, int lw, int rw) {
if (l > rw or r < lw) // bulundugumuz aralik cevabini aradigimiz araligin disinda.
return 0;
if (l >= lw and r <= rw) // cevabini aradigimiz aralik bu araligi tamamen kapsiyor.
return tree[ind];
int mid = (l + r) / 2;
// Agacta recursive bir sekilde araligimizi araliklara bolup gelen cevaplari birlestiyoruz.
return query(ind * 2, l, mid, lw, rw) + query(ind * 2 + 1, mid + 1, r, lw, rw);
}Dizideki
- Ağaçta
$x$ indeksli elemanı içeren tüm düğümlerin değerlerini güncelle.
Ağaçta
void update(int ind, int l, int r, int x, int val) {
if (l > x || r < x) // bulundugumuz aralik x indeksli elemani icermiyor.
return;
if (l == x and r == x) {
tree[ind] = val; // x indeksli elemani iceren yaprak dugumunun cevabini guncelliyoruz.
return;
}
int mid = (l + r) / 2;
// recursive bir sekilde x indeksli elemani iceren
// tum araliklarin cevaplarini guncelliyoruz.
update(ind * 2, l, mid, x, val);
update(ind * 2 + 1, mid + 1, r, x, val);
tree[ind] = tree[ind * 2] + tree[ind * 2 + 1];
}Segment Tree veri yapısı ile ilgili örnek bir probleme buradan{target="_blank"} ulaşabilirsiniz.