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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
| class LazySegmentTree: def __init__( self, data, merge_func, update_func, lazy_merge_func, default_val=0, lazy_default_val=0, ): """ Initialize a Lazy Segment Tree.
Parameters: data (list): The initial data array merge_func (function): Function to merge two values (lambda a, b: ...) update_func (function): Function to apply a tag to a value (lambda val, tag, l, r: ...) lazy_merge_func (function): Function to merge two tags (lambda old_tag, new_tag: ...) default_val: Default value for filling empty tree slots lazy_default_val: Default value for lazy tags """ self.n = len(data) self.merge = merge_func self.update = update_func self.lazy_merge = lazy_merge_func self.lazy_default_val = lazy_default_val
self.size = 1 while self.size < self.n: self.size <<= 1
self.tree = [default_val] * (2 * self.size) self.lazy = [self.lazy_default_val] * (2 * self.size)
for i in range(self.n): self.tree[self.size + i] = data[i] for i in range(self.size - 1, 0, -1): self.tree[i] = self.merge(self.tree[2 * i], self.tree[2 * i + 1])
def push_down(self, node, node_left, node_right): """ Push the lazy tag down to children nodes. """ if self.lazy[node] != self.lazy_default_val: mid = (node_left + node_right) // 2
left_node = 2 * node self.tree[left_node] = self.update( self.tree[left_node], self.lazy[node], node_left, mid ) if left_node < self.size: self.lazy[left_node] = self.lazy_merge( self.lazy[left_node], self.lazy[node] )
right_node = 2 * node + 1 self.tree[right_node] = self.update( self.tree[right_node], self.lazy[node], mid + 1, node_right ) if right_node < self.size: self.lazy[right_node] = self.lazy_merge( self.lazy[right_node], self.lazy[node] )
self.lazy[node] = self.lazy_default_val
def range_query(self, l, r): """ Query the value in range [l, r]. """ return self._range_query(1, 0, self.size - 1, l, r)
def _range_query(self, node, node_left, node_right, query_l, query_r): """ Helper function for recursive range query. """ if query_r < node_left or node_right < query_l: return None
if query_l <= node_left and node_right <= query_r: return self.tree[node]
self.push_down(node, node_left, node_right)
mid = (node_left + node_right) // 2 left_val = self._range_query(2 * node, node_left, mid, query_l, query_r) right_val = self._range_query( 2 * node + 1, mid + 1, node_right, query_l, query_r )
if left_val is not None and right_val is not None: return self.merge(left_val, right_val) return left_val if left_val is not None else right_val
def range_update(self, l, r, tag): """ Update range [l, r] with the given tag. """ self._range_update(1, 0, self.size - 1, l, r, tag)
def _range_update(self, node, node_left, node_right, update_l, update_r, tag): """ Helper function for recursive range update. """ if update_r < node_left or node_right < update_l: return
if update_l <= node_left and node_right <= update_r: self.tree[node] = self.update(self.tree[node], tag, node_left, node_right) if node < self.size: self.lazy[node] = ( self.lazy_merge(self.lazy[node], tag) if self.lazy[node] != self.lazy_default_val else tag ) return
self.push_down(node, node_left, node_right)
mid = (node_left + node_right) // 2 self._range_update(2 * node, node_left, mid, update_l, update_r, tag) self._range_update(2 * node + 1, mid + 1, node_right, update_l, update_r, tag)
self.tree[node] = self.merge(self.tree[2 * node], self.tree[2 * node + 1])
|