Skip to content

Commit 8b5b868

Browse files
authored
feat: add solutions to lc problem: No.2276 (#2104)
No.2276.Count Integers in Intervals
1 parent 2698d3f commit 8b5b868

File tree

5 files changed

+978
-44
lines changed

5 files changed

+978
-44
lines changed

solution/2200-2299/2276.Count Integers in Intervals/README.md

+339-2
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,20 @@ countIntervals.count(); // 返回 8
6262

6363
<!-- 这里可写通用的实现逻辑 -->
6464

65-
**方法一:线段树**
65+
**方法一:线段树(动态开点)**
6666

67-
区间求和问题,且值域较大,采用动态开点线段树。
67+
根据题目描述,我们需要维护一个区间集合,支持区间的添加和查询操作。对于区间的添加,我们可以使用线段树来维护区间集合。
68+
69+
线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 $\log(width)$。更新某个元素的值,只需要更新 $\log(width)$ 个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用**懒标记**保证效率。
70+
71+
- 线段树的每个节点代表一个区间;
72+
- 线段树具有唯一的根节点,代表的区间是整个统计范围,如 $[1,N]$;
73+
- 线段树的每个叶子节点代表一个长度为 $1$ 的元区间 $[x,x]$;
74+
- 对于每个内部节点 $[l,r]$,它的左儿子是 $[l,mid]$,右儿子是 $[mid+1,r]$, 其中 $mid=⌊(l+r)/2⌋$ (即向下取整)。
75+
76+
由于题目数据范围较大,我们可以使用动态开点的线段树来实现。动态开点的线段树是指,我们只在需要的时候才开点,而不是一开始就开好所有的点,这样可以节省空间。
77+
78+
时间复杂度方面,每次操作的时间复杂度为 $O(\log n)$。空间复杂度为 $O(m \times \log n)$。其中 $m$ 为操作次数,而 $n$ 为数据范围。
6879

6980
<!-- tabs:start -->
7081

@@ -117,6 +128,89 @@ class CountIntervals:
117128
# param_2 = obj.count()
118129
```
119130

131+
```python
132+
class Node:
133+
__slots__ = ("left", "right", "l", "r", "mid", "v", "add")
134+
135+
def __init__(self, l, r):
136+
self.left = None
137+
self.right = None
138+
self.l = l
139+
self.r = r
140+
self.mid = (l + r) // 2
141+
self.v = 0
142+
self.add = 0
143+
144+
145+
class SegmentTree:
146+
def __init__(self):
147+
self.root = Node(1, int(1e9) + 1)
148+
149+
def modify(self, l, r, v, node=None):
150+
if node is None:
151+
node = self.root
152+
if l > r:
153+
return
154+
if node.l >= l and node.r <= r:
155+
node.v = node.r - node.l + 1
156+
node.add = v
157+
return
158+
self.pushdown(node)
159+
if l <= node.mid:
160+
self.modify(l, r, v, node.left)
161+
if r > node.mid:
162+
self.modify(l, r, v, node.right)
163+
self.pushup(node)
164+
165+
def query(self, l, r, node=None):
166+
if node is None:
167+
node = self.root
168+
if l > r:
169+
return 0
170+
if node.l >= l and node.r <= r:
171+
return node.v
172+
self.pushdown(node)
173+
v = 0
174+
if l <= node.mid:
175+
v += self.query(l, r, node.left)
176+
if r > node.mid:
177+
v += self.query(l, r, node.right)
178+
return v
179+
180+
def pushup(self, node):
181+
node.v = node.left.v + node.right.v
182+
183+
def pushdown(self, node):
184+
if node.left is None:
185+
node.left = Node(node.l, node.mid)
186+
if node.right is None:
187+
node.right = Node(node.mid + 1, node.r)
188+
if node.add != 0:
189+
left, right = node.left, node.right
190+
left.add = node.add
191+
right.add = node.add
192+
left.v = left.r - left.l + 1
193+
right.v = right.r - right.l + 1
194+
node.add = 0
195+
196+
197+
class CountIntervals:
198+
def __init__(self):
199+
self.tree = SegmentTree()
200+
201+
def add(self, left, right):
202+
self.tree.modify(left, right, 1)
203+
204+
def count(self):
205+
return self.tree.query(1, int(1e9))
206+
207+
208+
# Your CountIntervals object will be instantiated and called as such:
209+
# obj = CountIntervals()
210+
# obj.add(left, right)
211+
# param_2 = obj.count()
212+
```
213+
120214
### **Java**
121215

122216
<!-- 这里可写当前语言的特殊实现逻辑 -->
@@ -234,6 +328,249 @@ class CountIntervals {
234328
*/
235329
```
236330

331+
### **C++**
332+
333+
```cpp
334+
class Node {
335+
public:
336+
Node(int l, int r)
337+
: l(l)
338+
, r(r)
339+
, mid((l + r) / 2)
340+
, v(0)
341+
, add(0)
342+
, left(nullptr)
343+
, right(nullptr) {}
344+
345+
int l, r, mid, v, add;
346+
Node* left;
347+
Node* right;
348+
};
349+
350+
class SegmentTree {
351+
public:
352+
SegmentTree()
353+
: root(new Node(1, 1000000001)) {}
354+
355+
void modify(int l, int r, int v, Node* node = nullptr) {
356+
if (node == nullptr) {
357+
node = root;
358+
}
359+
if (l > r) {
360+
return;
361+
}
362+
if (node->l >= l && node->r <= r) {
363+
node->v = node->r - node->l + 1;
364+
node->add = v;
365+
return;
366+
}
367+
pushdown(node);
368+
if (l <= node->mid) {
369+
modify(l, r, v, node->left);
370+
}
371+
if (r > node->mid) {
372+
modify(l, r, v, node->right);
373+
}
374+
pushup(node);
375+
}
376+
377+
int query(int l, int r, Node* node = nullptr) {
378+
if (node == nullptr) {
379+
node = root;
380+
}
381+
if (l > r) {
382+
return 0;
383+
}
384+
if (node->l >= l && node->r <= r) {
385+
return node->v;
386+
}
387+
pushdown(node);
388+
int v = 0;
389+
if (l <= node->mid) {
390+
v += query(l, r, node->left);
391+
}
392+
if (r > node->mid) {
393+
v += query(l, r, node->right);
394+
}
395+
return v;
396+
}
397+
398+
private:
399+
Node* root;
400+
401+
void pushup(Node* node) {
402+
node->v = node->left->v + node->right->v;
403+
}
404+
405+
void pushdown(Node* node) {
406+
if (node->left == nullptr) {
407+
node->left = new Node(node->l, node->mid);
408+
}
409+
if (node->right == nullptr) {
410+
node->right = new Node(node->mid + 1, node->r);
411+
}
412+
if (node->add != 0) {
413+
Node* left = node->left;
414+
Node* right = node->right;
415+
left->add = node->add;
416+
right->add = node->add;
417+
left->v = left->r - left->l + 1;
418+
right->v = right->r - right->l + 1;
419+
node->add = 0;
420+
}
421+
}
422+
};
423+
424+
class CountIntervals {
425+
public:
426+
CountIntervals() {}
427+
428+
void add(int left, int right) {
429+
tree.modify(left, right, 1);
430+
}
431+
432+
int count() {
433+
return tree.query(1, 1000000000);
434+
}
435+
436+
private:
437+
SegmentTree tree;
438+
};
439+
440+
/**
441+
* Your CountIntervals object will be instantiated and called as such:
442+
* CountIntervals* obj = new CountIntervals();
443+
* obj->add(left,right);
444+
* int param_2 = obj->count();
445+
*/
446+
```
447+
448+
### **Go**
449+
450+
```go
451+
type Node struct {
452+
left *Node
453+
right *Node
454+
l int
455+
r int
456+
mid int
457+
v int
458+
add int
459+
}
460+
461+
type SegmentTree struct {
462+
root *Node
463+
}
464+
465+
func newNode(l, r int) *Node {
466+
return &Node{
467+
left: nil,
468+
right: nil,
469+
l: l,
470+
r: r,
471+
mid: (l + r) / 2,
472+
v: 0,
473+
add: 0,
474+
}
475+
}
476+
477+
func newSegmentTree() *SegmentTree {
478+
return &SegmentTree{
479+
root: newNode(1, 1000000001),
480+
}
481+
}
482+
483+
func (st *SegmentTree) modify(l, r, v int, node *Node) {
484+
if node == nil {
485+
node = st.root
486+
}
487+
if l > r {
488+
return
489+
}
490+
if node.l >= l && node.r <= r {
491+
node.v = node.r - node.l + 1
492+
node.add = v
493+
return
494+
}
495+
st.pushdown(node)
496+
if l <= node.mid {
497+
st.modify(l, r, v, node.left)
498+
}
499+
if r > node.mid {
500+
st.modify(l, r, v, node.right)
501+
}
502+
st.pushup(node)
503+
}
504+
505+
func (st *SegmentTree) query(l, r int, node *Node) int {
506+
if node == nil {
507+
node = st.root
508+
}
509+
if l > r {
510+
return 0
511+
}
512+
if node.l >= l && node.r <= r {
513+
return node.v
514+
}
515+
st.pushdown(node)
516+
v := 0
517+
if l <= node.mid {
518+
v += st.query(l, r, node.left)
519+
}
520+
if r > node.mid {
521+
v += st.query(l, r, node.right)
522+
}
523+
return v
524+
}
525+
526+
func (st *SegmentTree) pushup(node *Node) {
527+
node.v = node.left.v + node.right.v
528+
}
529+
530+
func (st *SegmentTree) pushdown(node *Node) {
531+
if node.left == nil {
532+
node.left = newNode(node.l, node.mid)
533+
}
534+
if node.right == nil {
535+
node.right = newNode(node.mid+1, node.r)
536+
}
537+
if node.add != 0 {
538+
left := node.left
539+
right := node.right
540+
left.add = node.add
541+
right.add = node.add
542+
left.v = left.r - left.l + 1
543+
right.v = right.r - right.l + 1
544+
node.add = 0
545+
}
546+
}
547+
548+
type CountIntervals struct {
549+
tree *SegmentTree
550+
}
551+
552+
func Constructor() CountIntervals {
553+
return CountIntervals{
554+
tree: newSegmentTree(),
555+
}
556+
}
557+
558+
func (ci *CountIntervals) Add(left, right int) {
559+
ci.tree.modify(left, right, 1, nil)
560+
}
561+
562+
func (ci *CountIntervals) Count() int {
563+
return ci.tree.query(1, 1000000000, nil)
564+
}
565+
566+
/**
567+
* Your CountIntervals object will be instantiated and called as such:
568+
* obj := Constructor();
569+
* obj.Add(left,right);
570+
* param_2 := obj.Count();
571+
*/
572+
```
573+
237574
### **TypeScript**
238575

239576
```ts

0 commit comments

Comments
 (0)