@@ -62,9 +62,20 @@ countIntervals.count(); // 返回 8
62
62
63
63
<!-- 这里可写通用的实现逻辑 -->
64
64
65
- ** 方法一:线段树**
65
+ ** 方法一:线段树(动态开点) **
66
66
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$ 为数据范围。
68
79
69
80
<!-- tabs:start -->
70
81
@@ -117,6 +128,89 @@ class CountIntervals:
117
128
# param_2 = obj.count()
118
129
```
119
130
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
+
120
214
### ** Java**
121
215
122
216
<!-- 这里可写当前语言的特殊实现逻辑 -->
@@ -234,6 +328,249 @@ class CountIntervals {
234
328
*/
235
329
```
236
330
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
+
237
574
### ** TypeScript**
238
575
239
576
``` ts
0 commit comments