セグメントツリー
目次
参考
【木マスター養成講座】4-2. Segment 木ってなに〜?なんかうまく区間取ってくる編
RangeSumQuery
方針
区間を完全 2 分木で管理する
| 27 |
| 11 | 16 |
| 6 | 5 | 11 | 5 |
| 1 | 5 | 2 | 3 | 2 | 9 | 5 | 0 |
$\downarrow$
[27, 11, 16, 6, 5, 11, 5, 1, 5, 2, 3, 2, 9, 5, 0]
インデックスを割り当てる
| 27 |
[1] [2]
| 11 | 16 |
[2] [3] [4]
| 6 | 5 | 11 | 5 |
[4] [5] [6] [7] [8]
| 1 | 5 | 2 | 3 | 2 | 9 | 5 | 0 |
[8] [9] [10][11][12][13][14][15][16]
総和を取得する流れ
- $l$ について、$l$ が偶数なら上に($2$ で割る)、奇数なら右へ
- $r$ について、$r$ が偶数なら上に($2$ で割る)、奇数なら左へ
実装
class SegTree:
def __init__(self, n, arr=None):
self.seg_len = self.get_seglen(n)
self.arr = [0] * self.seg_len * 2
if arr:
for i, v in enumerate(arr):
self.add(i, v)
def add(self, i, val):
i += self.seg_len
self.arr[i] += val
while True:
i >>= 1
if i == 0:
break
self.arr[i] = self.arr[i*2] + self.arr[i*2+1]
def sum(self, l, r):
l += self.seg_len
r += self.seg_len
ans = 0
while l < r:
if l & 1:
ans += self.arr[l]
l += 1
l >>= 1
if r & 1:
ans += self.arr[r-1]
r -= 1
r >>= 1
return ans
@staticmethod
def get_seglen(n):
log2_n = 0
while n:
log2_n += 1
n >>= 1
return 1 << log2_n