Skip to content

Commit 499cddd

Browse files
committed
feat: add solutions to lc problem: No.2286
No.2286.Booking Concert Tickets in Groups
1 parent 642216e commit 499cddd

File tree

4 files changed

+44
-16
lines changed

4 files changed

+44
-16
lines changed

solution/2200-2299/2286.Booking Concert Tickets in Groups/README.md

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,40 @@ bms.scatter(5, 1); // 返回 False
6969

7070
**方法一:线段树**
7171

72+
分析题意我们得知:
73+
74+
- 对于 `gather(k, maxRow)` 操作,要求 $k$ 个人坐在同一行并且座位连续,也就是说,我们要找到最小的行,满足该行的剩余座位大于等于 $k$。
75+
- 对于 `scatter(k, maxRow)` 操作,只需要找到 $k$ 个座位就行,但是要求这 $k$ 个座位的行数尽可能小,因此,我们要找到第一个满足剩余座位数大于 $0$ 的行,进行座位分配,然后继续往后查找。
76+
77+
我们可以用线段树来实现。线段树每个节点的信息有:
78+
79+
- `l`:节点对应的区间左端点
80+
- `r`:节点对应的区间右端点
81+
- `s`:节点对应的区间总的剩余座位数
82+
- `mx`:节点对应的区间最大剩余座位数
83+
84+
注意,线段树节点区间的下标从 $1$ 开始。
85+
86+
线段树的操作有:
87+
88+
- `build(u, l, r)`:建立节点 $u$,对应区间 $[l, r]$,并递归建立其左右子节点。
89+
- `modify(u, x, v)`:从节点 $u$ 开始,找到对应区间 $[l, r]$ 中的第一个满足 $l = r = x$ 的节点,将该节点的 `s``mx` 修改为 $v$,并向上更新。
90+
- `query_sum(u, l, r)`:从节点 $u$ 开始,统计对应区间 $[l, r]$ 中的 `s` 之和。
91+
- `query_idx(u, l, r, k)`:从节点 $u$ 开始,找到对应区间 $[l, r]$ 中的第一个满足 `mx` 大于等于 $k$ 的节点,返回该节点的 `l`。查找时,我们从最大的区间 $[1, maxRow]$ 开始,由于我们要找最左边的满足 `mx` 大于等于 $k$ 的节点。因此,对于当前区间,我们判断前半部分区间的 `mx` 是否符合要求,是则说明答案就在前半部分区间,递归查找即可。否则说明答案在后半部分区间,递归查找后半部分区间。
92+
- `pushup(u)`:利用 $u$ 的子节点信息更新当前 $u$ 的信息。
93+
94+
对于 `gather(k, maxRow)` 操作,我们先用 `query_idx(1, 1, n, k)` 找到第一个满足剩余座位数大于等于 $k$ 的行,记为 $i$。然后我们用 `query_sum(1, i, i)` 得到该行的剩余座位数,记为 $s$。接下来,我们用 `modify(1, i, s - k)` 将该行的剩余座位数修改为 $s - k$,并向上更新。最后,我们返回 $[i - 1, m - s]$ 即可。
95+
96+
对于 `scatter(k, maxRow)` 操作,我们先用 `query_sum(1, 1, maxRow)` 统计前 $maxRow$ 行的剩余座位数,记为 $s$。如果 $s \lt k$,说明没有足够的座位,返回 `false`;否则,我们用 `query_idx(1, 1, maxRow, 1)` 找到第一个满足剩余座位数大于等于 $1$ 的行,记为 $i$。从该行开始,每次用 `query_sum(1, i, i)` 得到该行的剩余座位数,记为 $s_i$。如果 $s_i \geq k$,我们直接用 `modify(1, i, s_i - k)` 将该行的剩余座位数修改为 $s_i - k$,并向上更新,然后返回 `true`。否则,我们更新 $k = k - s_i$,然后将该行的剩余座位数修改为 $0$,并向上更新。最后,我们返回 `true`
97+
98+
时间复杂度:
99+
100+
- 初始化的时间复杂度为 $O(n)$。
101+
- `gather(k, maxRow)` 的时间复杂度为 $O(\log n)$。
102+
- `scatter(k, maxRow)` 的时间复杂度为 $O((n + q) \times \log n)$。
103+
104+
整体时间复杂度为 $O(n + q \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 和 $q$ 分别为行数和操作数。
105+
72106
<!-- tabs:start -->
73107

74108
### **Python3**
@@ -100,8 +134,7 @@ class SegmentTree:
100134

101135
def modify(self, u, x, v):
102136
if self.tr[u].l == x and self.tr[u].r == x:
103-
self.tr[u].s = v
104-
self.tr[u].mx = v
137+
self.tr[u].s = self.tr[u].mx = v
105138
return
106139
mid = (self.tr[u].l + self.tr[u].r) >> 1
107140
if x <= mid:
@@ -274,7 +307,7 @@ class BookMyShow {
274307
this.m = m;
275308
tree = new SegmentTree(n, m);
276309
}
277-
310+
278311
public int[] gather(int k, int maxRow) {
279312
++maxRow;
280313
int i = tree.queryIdx(1, 1, maxRow, k);
@@ -285,7 +318,7 @@ class BookMyShow {
285318
tree.modify(1, i, s - k);
286319
return new int[] {i - 1, (int) (m - s)};
287320
}
288-
321+
289322
public boolean scatter(int k, int maxRow) {
290323
++maxRow;
291324
if (tree.querySum(1, 1, maxRow) < k) {
@@ -335,8 +368,7 @@ public:
335368

336369
void modify(int u, int x, int v) {
337370
if (tr[u]->l == x && tr[u]->r == x) {
338-
tr[u]->s = v;
339-
tr[u]->mx = v;
371+
tr[u]->s = tr[u]->mx = v;
340372
return;
341373
}
342374
int mid = (tr[u]->l + tr[u]->r) >> 1;
@@ -411,7 +443,7 @@ public:
411443
this->m = m;
412444
tree = new SegmentTree(n, m);
413445
}
414-
446+
415447
vector<int> gather(int k, int maxRow) {
416448
++maxRow;
417449
int i = tree->queryIdx(1, 1, maxRow, k);
@@ -422,7 +454,7 @@ public:
422454
tree->modify(1, i, s - k);
423455
return {i - 1, (int) (m - s)};
424456
}
425-
457+
426458
bool scatter(int k, int maxRow) {
427459
++maxRow;
428460
if (tree->querySum(1, 1, maxRow) < k) {

solution/2200-2299/2286.Booking Concert Tickets in Groups/README_EN.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ class SegmentTree:
9090

9191
def modify(self, u, x, v):
9292
if self.tr[u].l == x and self.tr[u].r == x:
93-
self.tr[u].s = v
94-
self.tr[u].mx = v
93+
self.tr[u].s = self.tr[u].mx = v
9594
return
9695
mid = (self.tr[u].l + self.tr[u].r) >> 1
9796
if x <= mid:
@@ -323,8 +322,7 @@ public:
323322

324323
void modify(int u, int x, int v) {
325324
if (tr[u]->l == x && tr[u]->r == x) {
326-
tr[u]->s = v;
327-
tr[u]->mx = v;
325+
tr[u]->s = tr[u]->mx = v;
328326
return;
329327
}
330328
int mid = (tr[u]->l + tr[u]->r) >> 1;

solution/2200-2299/2286.Booking Concert Tickets in Groups/Solution.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ class SegmentTree {
1717

1818
void modify(int u, int x, int v) {
1919
if (tr[u]->l == x && tr[u]->r == x) {
20-
tr[u]->s = v;
21-
tr[u]->mx = v;
20+
tr[u]->s = tr[u]->mx = v;
2221
return;
2322
}
2423
int mid = (tr[u]->l + tr[u]->r) >> 1;

solution/2200-2299/2286.Booking Concert Tickets in Groups/Solution.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ def build(self, u, l, r):
2222

2323
def modify(self, u, x, v):
2424
if self.tr[u].l == x and self.tr[u].r == x:
25-
self.tr[u].s = v
26-
self.tr[u].mx = v
25+
self.tr[u].s = self.tr[u].mx = v
2726
return
2827
mid = (self.tr[u].l + self.tr[u].r) >> 1
2928
if x <= mid:

0 commit comments

Comments
 (0)