Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add solutions to lc problem: No.0732 #3921

Merged
merged 1 commit into from
Jan 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 136 additions & 16 deletions solution/0700-0799/0732.My Calendar III/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,21 @@ myCalendarThree.book(25, 55); // 返回 3

### 方法一:线段树

线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 $log(width)$。更新某个元素的值,只需要更新 $log(width)$ 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。
线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 $log(\text{width})$。更新某个元素的值,只需要更新 $log(\text{width})$ 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。

- 线段树的每个节点代表一个区间;
- 线段树具有唯一的根节点,代表的区间是整个统计范围,如 $[1,N]$;
- 线段树的每个叶子节点代表一个长度为 $1$ 的元区间 $[x, x]$;
- 对于每个内部节点 $[l,r]$,它的左儿子是 $[l,mid]$,右儿子是 $[mid+1,r]$, 其中 $mid = ⌊(l+r)/2⌋$ (即向下取整)。
- 对于每个内部节点 $[l,r]$,它的左儿子是 $[l,\text{mid}]$,右儿子是 $[\text{mid}+1,r]$, 其中 $\text{mid} = ⌊(l+r)/2⌋$ (即向下取整)。

对于本题,线段树节点维护的信息有:

1. 区间范围内被预定的次数的最大值 $v$
1. 懒标记 $add$
1. 懒标记 $\text{add}$

由于时间范围为 $10^9$,非常大,因此我们采用动态开点。

时间复杂度 $O(nlogn)$,其中 $n$ 表示日程安排的数量。
时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$,其中 $n$ 表示日程安排的数量。

<!-- tabs:start -->

Expand All @@ -105,7 +105,7 @@ class SegmentTree:
def __init__(self):
self.root = Node(1, int(1e9 + 1))

def modify(self, l, r, v, node=None):
def modify(self, l: int, r: int, v: int, node: Node = None):
if l > r:
return
if node is None:
Expand All @@ -121,7 +121,7 @@ class SegmentTree:
self.modify(l, r, v, node.right)
self.pushup(node)

def query(self, l, r, node=None):
def query(self, l: int, r: int, node: Node = None) -> int:
if l > r:
return 0
if node is None:
Expand All @@ -136,10 +136,10 @@ class SegmentTree:
v = max(v, self.query(l, r, node.right))
return v

def pushup(self, node):
def pushup(self, node: Node):
node.v = max(node.left.v, node.right.v)

def pushdown(self, node):
def pushdown(self, node: Node):
if node.left is None:
node.left = Node(node.l, node.mid)
if node.right is None:
Expand Down Expand Up @@ -312,15 +312,21 @@ public:
}

void modify(int l, int r, int v, Node* node) {
if (l > r) return;
if (l > r) {
return;
}
if (node->l >= l && node->r <= r) {
node->v += v;
node->add += v;
return;
}
pushdown(node);
if (l <= node->mid) modify(l, r, v, node->left);
if (r > node->mid) modify(l, r, v, node->right);
if (l <= node->mid) {
modify(l, r, v, node->left);
}
if (r > node->mid) {
modify(l, r, v, node->right);
}
pushup(node);
}

Expand All @@ -329,12 +335,18 @@ public:
}

int query(int l, int r, Node* node) {
if (l > r) return 0;
if (l > r) {
return 0;
}
if (node->l >= l && node->r <= r) return node->v;
pushdown(node);
int v = 0;
if (l <= node->mid) v = max(v, query(l, r, node->left));
if (r > node->mid) v = max(v, query(l, r, node->right));
if (l <= node->mid) {
v = max(v, query(l, r, node->left));
}
if (r > node->mid) {
v = max(v, query(l, r, node->right));
}
return v;
}

Expand All @@ -343,8 +355,12 @@ public:
}

void pushdown(Node* node) {
if (!node->left) node->left = new Node(node->l, node->mid);
if (!node->right) node->right = new Node(node->mid + 1, node->r);
if (!node->left) {
node->left = new Node(node->l, node->mid);
}
if (!node->right) {
node->right = new Node(node->mid + 1, node->r);
}
if (node->add) {
Node* left = node->left;
Node* right = node->right;
Expand Down Expand Up @@ -483,6 +499,110 @@ func (this *MyCalendarThree) Book(start int, end int) int {
*/
```

#### TypeScript

```ts
class Node {
left: Node | null = null;
right: Node | null = null;
l: number;
r: number;
mid: number;
v: number = 0;
add: number = 0;

constructor(l: number, r: number) {
this.l = l;
this.r = r;
this.mid = (l + r) >> 1;
}
}

class SegmentTree {
private root: Node = new Node(1, 1e9 + 1);

constructor() {}

modify(l: number, r: number, v: number, node: Node = this.root): void {
if (l > r) {
return;
}
if (node.l >= l && node.r <= r) {
node.v += v;
node.add += v;
return;
}
this.pushdown(node);
if (l <= node.mid) {
this.modify(l, r, v, node.left!);
}
if (r > node.mid) {
this.modify(l, r, v, node.right!);
}
this.pushup(node);
}

query(l: number, r: number, node: Node = this.root): number {
if (l > r) {
return 0;
}
if (node.l >= l && node.r <= r) {
return node.v;
}
this.pushdown(node);
let v = 0;
if (l <= node.mid) {
v = Math.max(v, this.query(l, r, node.left!));
}
if (r > node.mid) {
v = Math.max(v, this.query(l, r, node.right!));
}
return v;
}

private pushup(node: Node): void {
node.v = Math.max(node.left!.v, node.right!.v);
}

private pushdown(node: Node): void {
if (node.left === null) {
node.left = new Node(node.l, node.mid);
}
if (node.right === null) {
node.right = new Node(node.mid + 1, node.r);
}
if (node.add !== 0) {
const left = node.left!;
const right = node.right!;
left.add += node.add;
right.add += node.add;
left.v += node.add;
right.v += node.add;
node.add = 0;
}
}
}

class MyCalendarThree {
private tree: SegmentTree;

constructor() {
this.tree = new SegmentTree();
}

book(start: number, end: number): number {
this.tree.modify(start + 1, end, 1);
return this.tree.query(1, 1e9 + 1);
}
}

/**
* Your MyCalendarThree object will be instantiated and called as such:
* var obj = new MyCalendarThree()
* var param_1 = obj.book(startTime, endTime)
*/
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
Loading
Loading