-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsegment_tree.py
More file actions
65 lines (50 loc) · 1.5 KB
/
segment_tree.py
File metadata and controls
65 lines (50 loc) · 1.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
"""Basic implementation of a segment tree."""
left = lambda x: 2 * x
right = lambda x: 2 * x + 1
parent = lambda x: x // 2
index = lambda T, i: len(T) // 2 + i
def fill(tree, op):
internal = range(1, len(tree) // 2)
for idx in reversed(internal):
tree[idx] = op((tree[left(idx)], tree[right(idx)]))
def query_(t, l, r):
yield t[l] # yield t[r] in incl case
while True:
pl = parent(l)
pr = parent(r)
if pl == pr:
return
if l % 2 == 0:
yield t[right(pl)]
if r % 2 == 1:
yield t[left(pr)]
l = pl
r = pr
def query(t, l, r, op=sum):
return op(query_(t, l, r))
def update(tree, idx, value, op=sum):
tree[idx] = value
idx = parent(idx)
while idx > 0:
tree[idx] = op((tree[left(idx)], tree[right(idx)]))
idx = parent(idx)
def create_tree(data, op=sum):
t = [0] * len(data) + data
fill(t, op)
return t
class ArrayTree:
def __init__(self, data, op=sum):
d = [e for e in data]
self.tree = [0] * len(data) + d
self.op = op
fill(self.tree, self.op)
def __getitem__(self, q):
if isinstance(q, int):
return self.tree[index(self.tree, q)]
l, r = q.start, q.stop
l_idx = index(self.tree, l)
r_idx = index(self.tree, r)
return query(self.tree, l_idx, r_idx, op=self.op)
def __setitem__(self, idx, val):
i = index(self.tree, idx)
update(self.tree, i, val, op=self.op)