Kalıp #29
Segment Tree / BIT
İleriNokta güncelleme, aralık sorgusu O(log n); değişen önek toplam.
Ne zaman kullanılır
Nokta güncellemeleri ve aralık sorguları (sum, min, max, count) O(log n) gerekiyorsa. BIT tersinir işlemler (sum, xor); segment tree tersinmez (min, max) için.
Tanıma ipuçları
- Aralık sorgulu değişebilir dizi
- Nokta güncellemeli aralık toplamı
- Güncellemeli aralık min/max sorgusu
- Zamanla değişen önek toplamları
Yaygın tuzaklar
- BIT 1-indexed vs 0-indexed karışıklığı
- Aralık güncellemelerinde lazy propagation unutmak
- O(n) mümkünken treeyi O(n log n) kurmak
90 saniyelik tanıma egzersizi
Hangisi en iyi uyuyor?
- Aralık sorgulu değişebilir dizi
- Nokta güncellemeli aralık toplamı
- Güncellemeli aralık min/max sorgusu
Etkileşimli
Zihinsel model
Değişmezin tam adım adım anlatımı. Duraklat, noktalara tıkla veya ← → kullan. Her adımı kendi cümlelerinle anlatmayı hedefle.
yapraklar = elemanlar
Dizi [1,3,5,7]. Önek toplamlar mutasyonda ölür. Segment tree aralık toplamlarını saklar.
Nasıl düşünülür
Önek toplamı aralık toplamını O(1)’de verir, ama bir değer değişirse sonrasındaki her önek O(n)’de yeniden hesaplanmalı. Fenwick tree (BIT) bunu, i indeksinin lowbit(i) uzunluğunda aralığın toplamını sakladığı zekice bir dizi ile düzeltir. Güncelleme: her ata indekse ekle. Sorgu: her ata öneki topla. İkisi de bit hileleriyle O(log n).
Segment tree tersinmez işlemlere (min, max, count) genelleşir. Dizi üzerinde bir ikili ağaçtır: her düğüm aralığının agregatını saklar. Yapraklar elemanlar; iç düğümler iki çocuğu birleştirir. Nokta güncelleme bir kök-yaprak yolunda yürür; aralık sorgusu yalnızca örtüşen düğümlere iner. Aralık güncellemeleri ([l, r] aralığındaki her elemana v ekle) için lazy propagation ekle: çocuk güncellemelerini bir sorgu dokunana kadar ertele.
Şablon şekilleri
| Şekil | Temel hamle | Örnek |
|---|---|---|
| BIT (nokta, aralık toplam) | update(i, +v), query(r), query(l-1) |
LC 307 |
| Segment tree (aralık min/max) | Kur, nokta güncelle, sorguda birleştir | LC 315 |
| Lazy propagation (aralık ekle) | İnişte lazy tag it, dönüşte çek | LC 1649 |
| 2D segment tree | Satır × sütun ağaçların ağacı | LC 308 |
Karmaşıklık temeli
Kurulum: O(n) (veya naif O(n log n)). Güncelleme: O(log n). Sorgu: O(log n). Alan: BIT O(n), segment tree O(4n) (güvenli dizi boyutu). Lazy propagation ziyaret edilen düğüm başına O(1) ekler.
Şablondan probleme
- Karar ver: işlem tersinir mi (sum, xor) → BIT? Tersinmez mi (min, max) → segment tree?
- BIT için dahili olarak 1-indexed kullan (
update(i+1)); segment tree 0-indexed olabilir. - Aralık güncellemeleri için lazy propagation uygula veya BIT ile fark-dizisi hilesi kullan.
- Sorgular statikse (güncelleme yok) sade önek toplamı daha basit ve hızlıdır.
Şablon
TypeScript, Python ve C#’te aynı iskelet. Değişmezi uyarla; yapıyı koru.
/**
* Segment Tree / BIT template.
* This skeleton implements a Fenwick tree (BIT) for point-update range-sum.
* A segment tree handles the same range queries plus non-invertible operations
* (min, max, count); see the guide for the tree structure.
*/
export class BIT {
private n: number;
private tree: number[];
constructor(n: number) {
this.n = n;
this.tree = new Array<number>(n + 1).fill(0);
}
update(i: number, delta: number): void {
for (i++; i <= this.n; i += i & -i) this.tree[i]! += delta;
}
prefixSum(i: number): number {
let s = 0;
for (i++; i > 0; i -= i & -i) s += this.tree[i]!;
return s;
}
rangeSum(l: number, r: number): number {
return this.prefixSum(r) - (l > 0 ? this.prefixSum(l - 1) : 0);
}
}/**
* Segment Tree / BIT template.
* This skeleton implements a Fenwick tree (BIT) for point-update range-sum.
* A segment tree handles the same range queries plus non-invertible operations
* (min, max, count); see the guide for the tree structure.
*/
export class BIT {
private n: number;
private tree: number[];
constructor(n: number) {
this.n = n;
this.tree = new Array<number>(n + 1).fill(0);
}
update(i: number, delta: number): void {
for (i++; i <= this.n; i += i & -i) this.tree[i]! += delta;
}
prefixSum(i: number): number {
let s = 0;
for (i++; i > 0; i -= i & -i) s += this.tree[i]!;
return s;
}
rangeSum(l: number, r: number): number {
return this.prefixSum(r) - (l > 0 ? this.prefixSum(l - 1) : 0);
}
}- 1#307 Range Sum Query - MutableRehbermedium
- 2#308 Range Sum Query 2D - MutableRehbermedium
- 3#315 Count of Smaller Numbers After SelfRehberhard
- 4#327 Count of Range SumRehberhard
- 5#493 Reverse PairsRehberhard
- 6#1649 Create Sorted Array through InstructionsRehberhard