-
Notifications
You must be signed in to change notification settings - Fork 119
/
Copy pathBooking Concert Tickets in Groups.py
117 lines (101 loc) · 3.92 KB
/
Booking Concert Tickets in Groups.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
class Node:
def __init__(self, start, end):
self.s = start
self.e = end
self.left = None
self.right = None
self.total = 0 # for range sum query
self.mx = 0 # for range max query
class SegTree:
def __init__(self, start, end, val):
def build(l, r):
if l > r:
return None
if l == r:
node = Node(l, r)
node.total = val
node.mx = val
return node
node = Node(l, r)
m = (l + r) // 2
node.left = build(l, m)
node.right = build(m+1, r)
node.mx = max(node.left.mx, node.right.mx)
node.total = node.left.total + node.right.total
return node
self.root = build(start, end)
# update the total remain seats and the max remain seats for each node (range) in the segment tree
def update(self, index, val):
def updateHelper(node):
if node.s == node.e == index:
node.total -= val
node.mx -= val
return
m = (node.s + node.e) // 2
if index <= m:
updateHelper(node.left)
elif index > m:
updateHelper(node.right)
node.mx = max(node.left.mx, node.right.mx)
node.total = node.left.total + node.right.total
return
updateHelper(self.root)
def maxQuery(self, k, maxRow, seats):
def queryHelper(node):
if node.s == node.e:
# check if the row number is less than maxRow and the number of remains seats is greater or equal than k
if node.e > maxRow or node.total < k:
return []
if node.e <= maxRow and node.total >= k:
return [node.e, seats - node.total]
# we want to greedily search the left subtree to get the smallest row which has enough remain seats
if node.left.mx >= k:
return queryHelper(node.left)
return queryHelper(node.right)
return queryHelper(self.root)
def sumQuery(self, endRow):
def queryHelper(node, left, right):
if left <= node.s and node.e <= right:
return node.total
m = (node.s + node.e) // 2
if right <= m:
return queryHelper(node.left, left, right)
elif left > m:
return queryHelper(node.right, left, right)
return queryHelper(node.left, left, m) + queryHelper(node.right, m+1, right)
return queryHelper(self.root, 0, endRow)
class BookMyShow:
def __init__(self, n: int, m: int):
self.m = m
self.seg = SegTree(0, n-1, m)
# record the remain seats at each row
self.seats = [m] * n
# record the index of the smallest row that has remain seats > 0
self.startRow = 0
def gather(self, k: int, maxRow: int) -> List[int]:
res = self.seg.maxQuery(k, maxRow, self.m)
if res:
row = res[0]
self.seg.update(row, k)
self.seats[row] -= k
return res
def scatter(self, k: int, maxRow: int) -> bool:
if self.seg.sumQuery(maxRow) < k:
return False
else:
i = self.startRow
total = 0
while total < k:
prevTotal = total
total += self.seats[i]
if total < k:
# use up all the seats at ith row
self.seg.update(i, self.seats[i])
self.seats[i] = 0
i += 1
self.startRow = i
elif total >= k:
# occupy (k - prevTotal) seats at ith row
self.seg.update(i, k - prevTotal)
self.seats[i] -= k - prevTotal
return True