Skip to content

Commit 9ccbf99

Browse files
authored
feat: add solutions to lc problem: No.0715 (doocs#1954)
No.0715.Range Module
1 parent 1640e9d commit 9ccbf99

File tree

4 files changed

+448
-4
lines changed

4 files changed

+448
-4
lines changed

solution/0700-0799/0715.Range Module/README.md

+151-2
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,19 @@ rangeModule.queryRange(16, 17); 返回 true (尽管执行了删除操作,区
5454

5555
**方法一:线段树**
5656

57-
线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 $log(width)$。更新某个元素的值,只需要更新 $log(width)$ 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。
57+
根据题目描述,我们需要维护一个区间集合,支持区间的添加、删除和查询操作。对于区间的添加和删除操作,我们可以使用线段树来维护区间集合。
58+
59+
线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 $\log(width)$。更新某个元素的值,只需要更新 $\log(width)$ 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。
5860

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

66+
由于题目数据范围较大,我们可以使用动态开点的线段树来实现。动态开点的线段树是指,我们只在需要的时候才开点,而不是一开始就开好所有的点。这样可以节省空间,但是需要使用**懒标记**来维护区间修改。
67+
68+
时间复杂度方面,每次操作的时间复杂度为 $O(\log n)$。空间复杂度为 $O(m \times \log n)$。其中 $m$ 为操作次数,而 $n$ 为数据范围。
69+
6470
<!-- tabs:start -->
6571

6672
### **Python3**
@@ -69,6 +75,8 @@ rangeModule.queryRange(16, 17); 返回 true (尽管执行了删除操作,区
6975

7076
```python
7177
class Node:
78+
__slots__ = ['left', 'right', 'add', 'v']
79+
7280
def __init__(self):
7381
self.left = None
7482
self.right = None
@@ -77,6 +85,8 @@ class Node:
7785

7886

7987
class SegmentTree:
88+
__slots__ = ['root']
89+
8090
def __init__(self):
8191
self.root = Node()
8292

@@ -141,7 +151,6 @@ class RangeModule:
141151
def removeRange(self, left: int, right: int) -> None:
142152
self.tree.modify(left, right - 1, -1)
143153

144-
145154
# Your RangeModule object will be instantiated and called as such:
146155
# obj = RangeModule()
147156
# obj.addRange(left,right)
@@ -492,6 +501,146 @@ func (this *RangeModule) RemoveRange(left int, right int) {
492501
*/
493502
```
494503

504+
### **TypeScript**
505+
506+
```ts
507+
class Node {
508+
left: Node | null;
509+
right: Node | null;
510+
add: number;
511+
v: boolean;
512+
513+
constructor() {
514+
this.left = null;
515+
this.right = null;
516+
this.add = 0;
517+
this.v = false;
518+
}
519+
}
520+
521+
class SegmentTree {
522+
private root: Node;
523+
524+
constructor() {
525+
this.root = new Node();
526+
}
527+
528+
modify(
529+
left: number,
530+
right: number,
531+
v: number,
532+
l: number = 1,
533+
r: number = 1e9,
534+
node: Node | null = null,
535+
): void {
536+
if (node === null) {
537+
node = this.root;
538+
}
539+
540+
if (l >= left && r <= right) {
541+
node.v = v === 1;
542+
node.add = v;
543+
return;
544+
}
545+
546+
this.pushdown(node);
547+
548+
const mid = (l + r) >> 1;
549+
550+
if (left <= mid) {
551+
this.modify(left, right, v, l, mid, node.left);
552+
}
553+
554+
if (right > mid) {
555+
this.modify(left, right, v, mid + 1, r, node.right);
556+
}
557+
558+
this.pushup(node);
559+
}
560+
561+
query(
562+
left: number,
563+
right: number,
564+
l: number = 1,
565+
r: number = 1e9,
566+
node: Node | null = null,
567+
): boolean {
568+
if (node === null) {
569+
node = this.root;
570+
}
571+
572+
if (l >= left && r <= right) {
573+
return node.v;
574+
}
575+
576+
this.pushdown(node);
577+
578+
const mid = (l + r) >> 1;
579+
let result = true;
580+
581+
if (left <= mid) {
582+
result = result && this.query(left, right, l, mid, node.left);
583+
}
584+
585+
if (right > mid) {
586+
result = result && this.query(left, right, mid + 1, r, node.right);
587+
}
588+
589+
return result;
590+
}
591+
592+
pushup(node: Node): void {
593+
node.v = !!(node.left && node.left.v && node.right && node.right.v);
594+
}
595+
596+
pushdown(node: Node): void {
597+
if (node.left === null) {
598+
node.left = new Node();
599+
}
600+
601+
if (node.right === null) {
602+
node.right = new Node();
603+
}
604+
605+
if (node.add !== 0) {
606+
node.left.add = node.add;
607+
node.right.add = node.add;
608+
node.left.v = node.add === 1;
609+
node.right.v = node.add === 1;
610+
node.add = 0;
611+
}
612+
}
613+
}
614+
615+
class RangeModule {
616+
private tree: SegmentTree;
617+
618+
constructor() {
619+
this.tree = new SegmentTree();
620+
}
621+
622+
addRange(left: number, right: number): void {
623+
this.tree.modify(left, right - 1, 1);
624+
}
625+
626+
queryRange(left: number, right: number): boolean {
627+
return this.tree.query(left, right - 1);
628+
}
629+
630+
removeRange(left: number, right: number): void {
631+
this.tree.modify(left, right - 1, -1);
632+
}
633+
}
634+
635+
/**
636+
* Your RangeModule object will be instantiated and called as such:
637+
* var obj = new RangeModule()
638+
* obj.addRange(left,right)
639+
* var param_2 = obj.queryRange(left,right)
640+
* obj.removeRange(left,right)
641+
*/
642+
```
643+
495644
### **...**
496645

497646
```

solution/0700-0799/0715.Range Module/README_EN.md

+158-2
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,29 @@ rangeModule.queryRange(16, 17); // return True, (The number 16 in [16, 17) is st
4646

4747
## Solutions
4848

49-
Segment Tree.
49+
**Solution 1: Segment Tree**
50+
51+
According to the problem description, we need to maintain a set of intervals, supporting operations of interval addition, deletion, and query. For the addition and deletion of intervals, we can use a segment tree to maintain the set of intervals.
52+
53+
The segment tree divides the entire interval into multiple non-continuous sub-intervals, the number of which does not exceed $\log(width)$. To update the value of an element, only $\log(width)$ intervals need to be updated, and these intervals are all included in a large interval containing the element. When modifying the interval, we need to use **lazy propagation** to ensure efficiency.
54+
55+
- Each node of the segment tree represents an interval;
56+
- The segment tree has a unique root node, representing the entire statistical range, such as $[1,N]$;
57+
- Each leaf node of the segment tree represents an elementary interval of length $1$, $[x,x]$;
58+
- For each internal node $[l,r]$, its left child is $[l,mid]$, and the right child is $[mid+1,r]$, where $mid=⌊(l+r)/2⌋$ (rounded down).
59+
60+
Due to the large data range of the problem, we can implement it with a dynamically allocated segment tree. A dynamically allocated segment tree means that we only allocate nodes when needed, instead of allocating all nodes at the beginning. This can save space, but it requires **lazy propagation** to maintain interval modification.
61+
62+
In terms of time complexity, the time complexity of each operation is $O(\log n)$. The space complexity is $O(m \times \log n)$. Here, $m$ is the number of operations, and $n$ is the data range.
5063

5164
<!-- tabs:start -->
5265

5366
### **Python3**
5467

5568
```python
5669
class Node:
70+
__slots__ = ['left', 'right', 'add', 'v']
71+
5772
def __init__(self):
5873
self.left = None
5974
self.right = None
@@ -62,6 +77,8 @@ class Node:
6277

6378

6479
class SegmentTree:
80+
__slots__ = ['root']
81+
6582
def __init__(self):
6683
self.root = Node()
6784

@@ -126,7 +143,6 @@ class RangeModule:
126143
def removeRange(self, left: int, right: int) -> None:
127144
self.tree.modify(left, right - 1, -1)
128145

129-
130146
# Your RangeModule object will be instantiated and called as such:
131147
# obj = RangeModule()
132148
# obj.addRange(left,right)
@@ -475,6 +491,146 @@ func (this *RangeModule) RemoveRange(left int, right int) {
475491
*/
476492
```
477493

494+
### **TypeScript**
495+
496+
```ts
497+
class Node {
498+
left: Node | null;
499+
right: Node | null;
500+
add: number;
501+
v: boolean;
502+
503+
constructor() {
504+
this.left = null;
505+
this.right = null;
506+
this.add = 0;
507+
this.v = false;
508+
}
509+
}
510+
511+
class SegmentTree {
512+
private root: Node;
513+
514+
constructor() {
515+
this.root = new Node();
516+
}
517+
518+
modify(
519+
left: number,
520+
right: number,
521+
v: number,
522+
l: number = 1,
523+
r: number = 1e9,
524+
node: Node | null = null,
525+
): void {
526+
if (node === null) {
527+
node = this.root;
528+
}
529+
530+
if (l >= left && r <= right) {
531+
node.v = v === 1;
532+
node.add = v;
533+
return;
534+
}
535+
536+
this.pushdown(node);
537+
538+
const mid = (l + r) >> 1;
539+
540+
if (left <= mid) {
541+
this.modify(left, right, v, l, mid, node.left);
542+
}
543+
544+
if (right > mid) {
545+
this.modify(left, right, v, mid + 1, r, node.right);
546+
}
547+
548+
this.pushup(node);
549+
}
550+
551+
query(
552+
left: number,
553+
right: number,
554+
l: number = 1,
555+
r: number = 1e9,
556+
node: Node | null = null,
557+
): boolean {
558+
if (node === null) {
559+
node = this.root;
560+
}
561+
562+
if (l >= left && r <= right) {
563+
return node.v;
564+
}
565+
566+
this.pushdown(node);
567+
568+
const mid = (l + r) >> 1;
569+
let result = true;
570+
571+
if (left <= mid) {
572+
result = result && this.query(left, right, l, mid, node.left);
573+
}
574+
575+
if (right > mid) {
576+
result = result && this.query(left, right, mid + 1, r, node.right);
577+
}
578+
579+
return result;
580+
}
581+
582+
pushup(node: Node): void {
583+
node.v = !!(node.left && node.left.v && node.right && node.right.v);
584+
}
585+
586+
pushdown(node: Node): void {
587+
if (node.left === null) {
588+
node.left = new Node();
589+
}
590+
591+
if (node.right === null) {
592+
node.right = new Node();
593+
}
594+
595+
if (node.add !== 0) {
596+
node.left.add = node.add;
597+
node.right.add = node.add;
598+
node.left.v = node.add === 1;
599+
node.right.v = node.add === 1;
600+
node.add = 0;
601+
}
602+
}
603+
}
604+
605+
class RangeModule {
606+
private tree: SegmentTree;
607+
608+
constructor() {
609+
this.tree = new SegmentTree();
610+
}
611+
612+
addRange(left: number, right: number): void {
613+
this.tree.modify(left, right - 1, 1);
614+
}
615+
616+
queryRange(left: number, right: number): boolean {
617+
return this.tree.query(left, right - 1);
618+
}
619+
620+
removeRange(left: number, right: number): void {
621+
this.tree.modify(left, right - 1, -1);
622+
}
623+
}
624+
625+
/**
626+
* Your RangeModule object will be instantiated and called as such:
627+
* var obj = new RangeModule()
628+
* obj.addRange(left,right)
629+
* var param_2 = obj.queryRange(left,right)
630+
* obj.removeRange(left,right)
631+
*/
632+
```
633+
478634
### **...**
479635

480636
```

0 commit comments

Comments
 (0)