-
Notifications
You must be signed in to change notification settings - Fork 104
/
Copy pathset_range_sum.py
271 lines (240 loc) · 7.52 KB
/
set_range_sum.py
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# python3
import sys
class Vertex:
"""Vertex of a splay tree."""
def __init__(self, key, sum, left, right, parent):
self.key, self.sum, self.left, self.right, self.parent = \
key, sum, left, right, parent
class SplayTree:
"""Splay tree implementation."""
@staticmethod
def update(v):
"""Updates sum attribute of the given vertex."""
if v is None:
return
v.sum = v.key + (v.left.sum if v.left is not None else 0) + (
v.right.sum if v.right is not None else 0)
if v.left is not None:
v.left.parent = v
if v.right is not None:
v.right.parent = v
@classmethod
def _small_rotation(cls, v):
parent = v.parent
if parent is None:
return
grandparent = v.parent.parent
if parent.left == v:
m = v.right
v.right = parent
parent.left = m
else:
m = v.left
v.left = parent
parent.right = m
cls.update(parent)
cls.update(v)
v.parent = grandparent
if grandparent is not None:
if grandparent.left == parent:
grandparent.left = v
else:
grandparent.right = v
@classmethod
def _big_rotation(cls, v):
if v.parent.left == v and v.parent.parent.left == v.parent:
# Zig-zig
cls._small_rotation(v.parent)
cls._small_rotation(v)
elif v.parent.right == v and v.parent.parent.right == v.parent:
# Zig-zig
cls._small_rotation(v.parent)
cls._small_rotation(v)
else:
# Zig-zag
cls._small_rotation(v)
cls._small_rotation(v)
@classmethod
def splay(cls, v):
"""Makes splay of the given vertex and makes it the new root."""
if v is None:
return None
while v.parent is not None:
if v.parent.parent is None:
cls._small_rotation(v)
break
cls._big_rotation(v)
return v
@classmethod
def find(cls, root, key):
"""Searches for the given key in the tree with the given root
and calls splay for the deepest visited node after that.
Returns pair of the result and the new root.
If found, result is a pointer to the node with the given key.
Otherwise, result is a pointer to the node with the smallest
bigger key (next value in the order).
If the key is bigger than all keys in the tree,
then result is None.
"""
v = root
last = root
next_ = None
while v is not None:
if v.key >= key and (next_ is None or v.key < next_.key):
next_ = v
last = v
if v.key == key:
break
if v.key < key:
v = v.right
else:
v = v.left
root = cls.splay(last)
return next_, root
@classmethod
def split(cls, root, key):
"""Splits the tree into two subtrees by given integer.
Returns two roots of the left and right subtrees correspondingly.
"""
result, root = SplayTree.find(root, key)
if result is None:
return root, None
right = cls.splay(result)
left = right.left
right.left = None
if left is not None:
left.parent = None
cls.update(left)
cls.update(right)
return left, right
@classmethod
def merge(cls, left, right):
"""Merges two trees by given vertices.
Returns new root.
"""
if left is None:
return right
if right is None:
return left
while right.left is not None:
right = right.left
right = cls.splay(right)
right.left = left
cls.update(right)
return right
class Set:
"""Set with range sums.
Stores a set of integers and quickly computes range sums.
Samples:
>>> s = Set()
>>> s.search(1)
>>> s.insert(1)
>>> s.search(1)
1
>>> s.insert(2)
>>> s.sum(1, 2)
3
>>> s.insert(2)
>>> s.search(2)
2
>>> s.erase(2)
>>> s.search(2)
>>> s.sum(1, 2)
1
>>> s.erase(3)
>>> s.search(3)
>>> s.erase(1)
>>> s.insert(10)
>>> s.sum(1, 10)
10
>>>
>>> # Explanation:
>>> # Adding the same element twice doesn't change the set.
>>> # Attempts to remove an element which is not the set are ignored.
>>>
>>> s = Set()
>>> s.search(0)
>>> s.insert(0)
>>> s.search(0)
0
>>> s.erase(0)
>>> s.search(0)
>>>
>>> # Explanation:
>>> # First, 0 is not in the set. Then it is added to the set.
>>> # Then it is removed from the set.
>>>
>>> s = Set()
>>> s.insert(491572259)
>>> s.search(491572259)
491572259
>>> s.search(899375874)
>>> s.sum(310971296, 877523306)
491572259
>>> s.insert(352411209)
>>>
>>> # Explanation:
>>> # First, 491572259 is added to the set, then it is found there.
>>> # Number 899375874 is not in the set. The only number in the set is
>>> # now 491572259, and it is in the range between 310971296 and 877523306,
>>> # so the sum of all numbers in this range is equal to 491572259.
"""
root = None
def insert(self, key):
"""Inserts integer into the set."""
left, right = SplayTree.split(self.root, key)
new_vertex = None
if right is None or right.key != key:
new_vertex = Vertex(key, key, None, None, None)
self.root = SplayTree.merge(SplayTree.merge(left, new_vertex), right)
def erase(self, key):
"""Removes integer from the set."""
if self.search(key) is None:
return
SplayTree.splay(self.root)
self.root = SplayTree.merge(self.root.left, self.root.right)
if self.root is not None:
self.root.parent = None
def search(self, key):
"""Checks whether integer is in the set or not."""
result, self.root = SplayTree.find(self.root, key)
if result is None or result.key != key:
return None
return result.key
def sum(self, fr, to):
"""Returns the sum of all elements in the set within range [fr:to]."""
left, middle = SplayTree.split(self.root, fr)
middle, right = SplayTree.split(middle, to + 1)
if middle is None:
ans = 0
self.root = SplayTree.merge(left, right)
else:
ans = middle.sum
self.root = SplayTree.merge(SplayTree.merge(left, middle), right)
return ans
if __name__ == "__main__":
n = int(sys.stdin.readline())
last_sum_result = 0
MODULO = 1000000001
s = Set()
for i in range(n):
line = sys.stdin.readline().split()
if line[0] == "+":
x = int(line[1])
s.insert((x + last_sum_result) % MODULO)
elif line[0] == "-":
x = int(line[1])
s.erase((x + last_sum_result) % MODULO)
elif line[0] == "?":
x = int(line[1])
print(
"Found" if s.search(
(x + last_sum_result) % MODULO) is not None else "Not found"
)
elif line[0] == "s":
l = int(line[1])
r = int(line[2])
res = s.sum((l + last_sum_result) % MODULO,
(r + last_sum_result) % MODULO)
print(res)
last_sum_result = res % MODULO