-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathminimum-operations-to-equalize-subarrays.py
More file actions
77 lines (70 loc) · 2.9 KB
/
minimum-operations-to-equalize-subarrays.py
File metadata and controls
77 lines (70 loc) · 2.9 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
66
67
68
69
70
71
72
73
74
75
76
77
# Time: O((n + q) * logn)
# Space: O(nlogn)
# prefix sum, persistent segment tree, binary search
class PersistentSegmentTree(object):
LEFT, RIGHT, CNT, TOTAL = range(4)
def __init__(self, vals):
self.sorted_unique_vals = sorted(set(vals))
self.val_to_idx = {x: i for i, x in enumerate(self.sorted_unique_vals)}
self.n = len(self.val_to_idx)
self.roots = []
self.__build(vals)
def __new_node(self):
return [None, None, 0, 0]
def __build(self, vals):
root = self.__new_node()
self.roots.append(root)
for x in vals:
root = root[:]
self.roots.append(root)
curr = root
left, right = 0, self.n-1
i = self.val_to_idx[x]
while left < right:
curr[self.CNT] += 1
curr[self.TOTAL] += x
mid = left+(right-left)//2
if i <= mid:
curr[self.LEFT] = curr = curr[self.LEFT][:] if curr[self.LEFT] else self.__new_node()
right = mid
else:
curr[self.RIGHT] = curr = curr[self.RIGHT][:] if curr[self.RIGHT] else self.__new_node()
left = mid+1
curr[self.CNT] += 1
curr[self.TOTAL] += x
def query(self, l, r):
a, b = self.roots[l], self.roots[r+1]
left_cnt = left_total = 0
med_cnt = (r-l+1)//2+1
left, right = 0, self.n-1
while left < right:
mid = left+(right-left)//2
cnt = ((b[self.LEFT][self.CNT] if b and b[self.LEFT] else 0)-
(a[self.LEFT][self.CNT] if a and a[self.LEFT] else 0))
if med_cnt <= cnt:
a = a[self.LEFT] if a else None
b = b[self.LEFT] if b else None
right = mid
else:
med_cnt -= cnt
left_cnt += cnt
left_total += ((b[self.LEFT][self.TOTAL] if b and b[self.LEFT] else 0)-
(a[self.LEFT][self.TOTAL] if a and a[self.LEFT] else 0))
a = a[self.RIGHT] if a else None
b = b[self.RIGHT] if b else None
left = mid+1
return ((self.sorted_unique_vals[left]*left_cnt-left_total)+((self.roots[r+1][self.TOTAL]-
self.roots[l][self.TOTAL]-left_total)-self.sorted_unique_vals[left]*((r-l+1)-left_cnt)))
class Solution(object):
def minOperations(self, nums, k, queries):
"""
:type nums: List[int]
:type k: int
:type queries: List[List[int]]
:rtype: List[int]
"""
prefix = [0]*(len(nums)+1)
for i, x in enumerate(nums):
prefix[i+1] = prefix[i]+(1 if i-1 >= 0 and nums[i]%k != nums[i-1]%k else 0)
pst = PersistentSegmentTree([x//k for x in nums])
return [pst.query(s, t) if prefix[t+1]-prefix[s+1] == 0 else -1 for s, t in queries]