1
1
from __future__ import annotations
2
2
3
-
4
3
class Node :
5
4
def __init__ (self , value : int = 0 ) -> None :
6
5
self .value : int = value
7
6
self .left : Node | None = None
8
7
self .right : Node | None = None
9
8
10
-
11
9
class PersistentSegmentTree :
12
10
def __init__ (self , arr : list [int ]) -> None :
13
11
self .n : int = len (arr )
@@ -54,22 +52,10 @@ def update(self, version: int, index: int, value: int) -> int:
54
52
self .roots .append (new_root )
55
53
return len (self .roots ) - 1
56
54
57
- def _update (self , node : Node , start : int , end : int , index : int , value : int ) -> Node :
58
- """
59
- Updates the node for the specified index and value and returns the new node.
55
+ def _update (self , node : Node | None , start : int , end : int , index : int , value : int ) -> Node :
56
+ if node is None :
57
+ raise ValueError ( "Cannot update a None node" )
60
58
61
- >>> pst = PersistentSegmentTree([1, 2, 3, 4])
62
- >>> old_root = pst.roots[0]
63
- >>> new_root = pst._update(old_root, 0, 3, 1, 5) # Update index 1 to 5
64
- >>> new_root.value # New sum after update
65
- 13
66
- >>> old_root.value # Old root remains unchanged
67
- 10
68
- >>> new_root.left.value # Updated left child
69
- 6
70
- >>> new_root.right.value # Right child remains the same
71
- 7
72
- """
73
59
if start == end :
74
60
return Node (value )
75
61
@@ -78,14 +64,12 @@ def _update(self, node: Node, start: int, end: int, index: int, value: int) -> N
78
64
79
65
if index <= mid :
80
66
new_node .left = self ._update (node .left , start , mid , index , value )
81
- new_node .right = node .right # Ensure right node is the same as the original
67
+ new_node .right = node .right
82
68
else :
83
- new_node .left = node .left # Ensure left node is the same as the original
69
+ new_node .left = node .left
84
70
new_node .right = self ._update (node .right , mid + 1 , end , index , value )
85
71
86
- new_node .value = new_node .left .value + (
87
- new_node .right .value if new_node .right else 0
88
- )
72
+ new_node .value = new_node .left .value + (new_node .right .value if new_node .right else 0 )
89
73
90
74
return new_node
91
75
@@ -101,38 +85,26 @@ def query(self, version: int, left: int, right: int) -> int:
101
85
>>> version_1 = pst.update(0, 1, 5) # Update index 1 to 5
102
86
>>> pst.query(version_1, 0, 3) # Sum of all elements in new version
103
87
13
104
- >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2
88
+ >>> pst.query(version_1, 1, 2) # Sum of elements at index 1 and 2 in new version
105
89
8
106
90
"""
107
91
return self ._query (self .roots [version ], 0 , self .n - 1 , left , right )
108
92
109
- def _query (self , node : Node , start : int , end : int , left : int , right : int ) -> int :
110
- """
111
- Queries the sum of values in the range [left, right] for the given node.
93
+ def _query (self , node : Node | None , start : int , end : int , left : int , right : int ) -> int :
94
+ if node is None :
95
+ return 0
112
96
113
- >>> pst = PersistentSegmentTree([1, 2, 3, 4])
114
- >>> root = pst.roots[0]
115
- >>> pst._query(root, 0, 3, 1, 2) # Sum of elements at index 1 and 2
116
- 5
117
- >>> pst._query(root, 0, 3, 0, 3) # Sum of all elements
118
- 10
119
- >>> pst._query(root, 0, 3, 2, 3) # Sum of elements at index 2 and 3
120
- 7
121
- """
122
- if node is None or left > end or right < start :
97
+ if left > end or right < start :
123
98
return 0
124
99
if left <= start and right >= end :
125
100
return node .value
126
101
mid = (start + end ) // 2
127
- return self ._query (node .left , start , mid , left , right ) + self ._query (
128
- node .right , mid + 1 , end , left , right
129
- )
130
-
102
+ return (self ._query (node .left , start , mid , left , right ) +
103
+ self ._query (node .right , mid + 1 , end , left , right ))
131
104
132
105
# Running the doctests
133
106
if __name__ == "__main__" :
134
107
import doctest
135
-
136
108
print ("Running doctests..." )
137
109
result = doctest .testmod ()
138
110
print (f"Ran { result .attempted } tests, { result .failed } failed." )
0 commit comments