| 45 | |
| 46 | |
| 47 | class SegmentTree[T]: |
| 48 | def __init__(self, arr: list[T], fnc: Callable[[T, T], T]) -> None: |
| 49 | """ |
| 50 | Segment Tree constructor, it works just with commutative combiner. |
| 51 | :param arr: list of elements for the segment tree |
| 52 | :param fnc: commutative function for combine two elements |
| 53 | |
| 54 | >>> SegmentTree(['a', 'b', 'c'], lambda a, b: f'{a}{b}').query(0, 2) |
| 55 | 'abc' |
| 56 | >>> SegmentTree([(1, 2), (2, 3), (3, 4)], |
| 57 | ... lambda a, b: (a[0] + b[0], a[1] + b[1])).query(0, 2) |
| 58 | (6, 9) |
| 59 | """ |
| 60 | any_type: Any | T = None |
| 61 | |
| 62 | self.N: int = len(arr) |
| 63 | self.st: list[T] = [any_type for _ in range(self.N)] + arr |
| 64 | self.fn = fnc |
| 65 | self.build() |
| 66 | |
| 67 | def build(self) -> None: |
| 68 | for p in range(self.N - 1, 0, -1): |
| 69 | self.st[p] = self.fn(self.st[p * 2], self.st[p * 2 + 1]) |
| 70 | |
| 71 | def update(self, p: int, v: T) -> None: |
| 72 | """ |
| 73 | Update an element in log(N) time |
| 74 | :param p: position to be update |
| 75 | :param v: new value |
| 76 | |
| 77 | >>> st = SegmentTree([3, 1, 2, 4], min) |
| 78 | >>> st.query(0, 3) |
| 79 | 1 |
| 80 | >>> st.update(2, -1) |
| 81 | >>> st.query(0, 3) |
| 82 | -1 |
| 83 | """ |
| 84 | p += self.N |
| 85 | self.st[p] = v |
| 86 | while p > 1: |
| 87 | p = p // 2 |
| 88 | self.st[p] = self.fn(self.st[p * 2], self.st[p * 2 + 1]) |
| 89 | |
| 90 | def query(self, left: int, right: int) -> T | None: |
| 91 | """ |
| 92 | Get range query value in log(N) time |
| 93 | :param left: left element index |
| 94 | :param right: right element index |
| 95 | :return: element combined in the range [left, right] |
| 96 | |
| 97 | >>> st = SegmentTree([1, 2, 3, 4], lambda a, b: a + b) |
| 98 | >>> st.query(0, 2) |
| 99 | 6 |
| 100 | >>> st.query(1, 2) |
| 101 | 5 |
| 102 | >>> st.query(0, 3) |
| 103 | 10 |
| 104 | >>> st.query(2, 3) |
no outgoing calls
no test coverage detected