binary-tree-typed 2.4.5 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +0 -84
  2. package/dist/cjs/index.cjs +1476 -404
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs-legacy/index.cjs +1473 -401
  5. package/dist/cjs-legacy/index.cjs.map +1 -1
  6. package/dist/esm/index.mjs +1476 -404
  7. package/dist/esm/index.mjs.map +1 -1
  8. package/dist/esm-legacy/index.mjs +1473 -401
  9. package/dist/esm-legacy/index.mjs.map +1 -1
  10. package/dist/types/data-structures/base/index.d.ts +1 -0
  11. package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
  12. package/dist/types/data-structures/base/iterable-entry-base.d.ts +8 -8
  13. package/dist/types/data-structures/base/linear-base.d.ts +3 -3
  14. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +380 -51
  15. package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +487 -147
  16. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +956 -80
  17. package/dist/types/data-structures/binary-tree/bst.d.ts +816 -29
  18. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +610 -31
  19. package/dist/types/data-structures/binary-tree/segment-tree.d.ts +326 -135
  20. package/dist/types/data-structures/binary-tree/tree-map.d.ts +3781 -6
  21. package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +3607 -201
  22. package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +2874 -65
  23. package/dist/types/data-structures/binary-tree/tree-set.d.ts +3528 -6
  24. package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -4
  25. package/dist/types/data-structures/graph/directed-graph.d.ts +429 -47
  26. package/dist/types/data-structures/graph/map-graph.d.ts +59 -1
  27. package/dist/types/data-structures/graph/undirected-graph.d.ts +393 -59
  28. package/dist/types/data-structures/hash/hash-map.d.ts +473 -89
  29. package/dist/types/data-structures/heap/heap.d.ts +581 -99
  30. package/dist/types/data-structures/heap/max-heap.d.ts +46 -0
  31. package/dist/types/data-structures/heap/min-heap.d.ts +59 -0
  32. package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +646 -47
  33. package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +596 -68
  34. package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +793 -12
  35. package/dist/types/data-structures/matrix/matrix.d.ts +499 -0
  36. package/dist/types/data-structures/priority-queue/max-priority-queue.d.ts +57 -0
  37. package/dist/types/data-structures/priority-queue/min-priority-queue.d.ts +60 -0
  38. package/dist/types/data-structures/priority-queue/priority-queue.d.ts +60 -0
  39. package/dist/types/data-structures/queue/deque.d.ts +593 -71
  40. package/dist/types/data-structures/queue/queue.d.ts +463 -42
  41. package/dist/types/data-structures/stack/stack.d.ts +384 -32
  42. package/dist/types/data-structures/trie/trie.d.ts +470 -48
  43. package/dist/types/interfaces/graph.d.ts +1 -1
  44. package/dist/types/types/common.d.ts +2 -2
  45. package/dist/types/types/data-structures/binary-tree/segment-tree.d.ts +1 -1
  46. package/dist/types/types/data-structures/heap/heap.d.ts +1 -0
  47. package/dist/types/types/data-structures/linked-list/skip-linked-list.d.ts +1 -4
  48. package/dist/types/types/data-structures/priority-queue/priority-queue.d.ts +1 -0
  49. package/dist/types/types/utils/validate-type.d.ts +4 -4
  50. package/dist/umd/binary-tree-typed.js +1469 -397
  51. package/dist/umd/binary-tree-typed.js.map +1 -1
  52. package/dist/umd/binary-tree-typed.min.js +5 -5
  53. package/dist/umd/binary-tree-typed.min.js.map +1 -1
  54. package/package.json +2 -2
  55. package/src/data-structures/base/index.ts +1 -0
  56. package/src/data-structures/base/iterable-element-base.ts +4 -5
  57. package/src/data-structures/base/iterable-entry-base.ts +8 -8
  58. package/src/data-structures/base/linear-base.ts +3 -3
  59. package/src/data-structures/binary-tree/avl-tree.ts +386 -51
  60. package/src/data-structures/binary-tree/binary-indexed-tree.ts +596 -247
  61. package/src/data-structures/binary-tree/binary-tree.ts +956 -81
  62. package/src/data-structures/binary-tree/bst.ts +840 -35
  63. package/src/data-structures/binary-tree/red-black-tree.ts +689 -97
  64. package/src/data-structures/binary-tree/segment-tree.ts +498 -249
  65. package/src/data-structures/binary-tree/tree-map.ts +3784 -7
  66. package/src/data-structures/binary-tree/tree-multi-map.ts +3614 -211
  67. package/src/data-structures/binary-tree/tree-multi-set.ts +2874 -65
  68. package/src/data-structures/binary-tree/tree-set.ts +3531 -10
  69. package/src/data-structures/graph/abstract-graph.ts +4 -4
  70. package/src/data-structures/graph/directed-graph.ts +429 -47
  71. package/src/data-structures/graph/map-graph.ts +59 -1
  72. package/src/data-structures/graph/undirected-graph.ts +393 -59
  73. package/src/data-structures/hash/hash-map.ts +476 -92
  74. package/src/data-structures/heap/heap.ts +581 -99
  75. package/src/data-structures/heap/max-heap.ts +46 -0
  76. package/src/data-structures/heap/min-heap.ts +59 -0
  77. package/src/data-structures/linked-list/doubly-linked-list.ts +646 -47
  78. package/src/data-structures/linked-list/singly-linked-list.ts +596 -68
  79. package/src/data-structures/linked-list/skip-linked-list.ts +1067 -90
  80. package/src/data-structures/matrix/matrix.ts +584 -12
  81. package/src/data-structures/priority-queue/max-priority-queue.ts +57 -0
  82. package/src/data-structures/priority-queue/min-priority-queue.ts +60 -0
  83. package/src/data-structures/priority-queue/priority-queue.ts +60 -0
  84. package/src/data-structures/queue/deque.ts +592 -70
  85. package/src/data-structures/queue/queue.ts +463 -42
  86. package/src/data-structures/stack/stack.ts +384 -32
  87. package/src/data-structures/trie/trie.ts +470 -48
  88. package/src/interfaces/graph.ts +1 -1
  89. package/src/types/common.ts +2 -2
  90. package/src/types/data-structures/binary-tree/segment-tree.ts +1 -1
  91. package/src/types/data-structures/heap/heap.ts +1 -0
  92. package/src/types/data-structures/linked-list/skip-linked-list.ts +2 -1
  93. package/src/types/data-structures/priority-queue/priority-queue.ts +1 -0
  94. package/src/types/utils/validate-type.ts +4 -4
@@ -2,323 +2,572 @@
2
2
  * data-structure-typed
3
3
  *
4
4
  * @author Pablo Zeng
5
- * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
6
5
  * @license MIT License
7
6
  */
8
7
 
9
- import type { SegmentTreeNodeVal } from '../../types';
8
+ export type SegmentTreeOptions<E> = {
9
+ merger: (a: E, b: E) => E;
10
+ identity: E;
11
+ };
10
12
 
11
- export class SegmentTreeNode {
12
- /**
13
- * The constructor initializes the properties of a SegmentTreeNode object.
14
- * @param {number} start - The `start` parameter represents the starting index of the segment covered
15
- * by this node in a segment tree.
16
- * @param {number} end - The `end` parameter represents the end index of the segment covered by this
17
- * node in a segment tree.
18
- * @param {number} sum - The `sum` parameter represents the sum of the values in the range covered by
19
- * the segment tree node.
20
- * @param {SegmentTreeNodeVal | undefined} [value] - The `value` parameter is an optional parameter
21
- * of type `SegmentTreeNodeVal`. It represents the value associated with the segment tree node.
22
- */
23
- constructor(start: number, end: number, sum: number, value?: SegmentTreeNodeVal | undefined) {
24
- this._start = start;
25
- this._end = end;
26
- this._sum = sum;
27
- this._value = value || undefined;
13
+ /**
14
+ * Generic Segment Tree with flat array internals.
15
+ *
16
+ * Supports any associative merge operation (sum, min, max, gcd, etc.).
17
+ * Reference: AtCoder Library segtree<S, op, e>.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const sumTree = SegmentTree.sum([1, 2, 3, 4, 5]);
22
+ * sumTree.query(1, 3); // 9 (2+3+4)
23
+ * sumTree.update(2, 10); // [1, 2, 10, 4, 5]
24
+ * sumTree.query(1, 3); // 16 (2+10+4)
25
+ *
26
+ * const minTree = SegmentTree.min([5, 2, 8, 1, 9]);
27
+ * minTree.query(0, 4); // 1
28
+ * ```
29
+ */
30
+ export class SegmentTree<E = number> implements Iterable<E> {
31
+ protected readonly _merger: (a: E, b: E) => E;
32
+ protected readonly _identity: E;
33
+ protected _n: number; // number of leaf elements
34
+ protected _tree: E[]; // flat array, 1-indexed, size 2*_size
35
+ protected _treeSize: number; // internal tree size (next power of 2 >= _n)
36
+
37
+ constructor(elements: E[], options: SegmentTreeOptions<E>) {
38
+ this._merger = options.merger;
39
+ this._identity = options.identity;
40
+ this._n = elements.length;
41
+
42
+ // Round up to next power of 2
43
+ this._treeSize = 1;
44
+ while (this._treeSize < this._n) this._treeSize <<= 1;
45
+
46
+ // Allocate and fill with identity
47
+ this._tree = new Array(2 * this._treeSize).fill(this._identity);
48
+
49
+ // Place elements in leaves
50
+ for (let i = 0; i < this._n; i++) {
51
+ this._tree[this._treeSize + i] = elements[i];
52
+ }
53
+
54
+ // Build internal nodes bottom-up
55
+ for (let i = this._treeSize - 1; i >= 1; i--) {
56
+ this._tree[i] = this._merger(this._tree[2 * i], this._tree[2 * i + 1]);
57
+ }
28
58
  }
29
59
 
30
- protected _start = 0;
60
+ // ─── Convenience factories ─────────────────────────────────
31
61
 
32
62
  /**
33
- * The function returns the value of the protected variable _start.
34
- * @returns The start value, which is of type number.
63
+ * Create a sum segment tree.
64
+ * @example
65
+ * ```ts
66
+ * const st = SegmentTree.sum([1, 2, 3, 4, 5]);
67
+ * st.query(0, 2); // 6 (1+2+3)
68
+ * st.update(1, 10);
69
+ * st.query(0, 2); // 14 (1+10+3)
70
+ * ```
35
71
  */
36
- get start(): number {
37
- return this._start;
72
+ static sum(elements: number[]): SegmentTree<number> {
73
+ return new SegmentTree<number>(elements, {
74
+ merger: (a, b) => a + b,
75
+ identity: 0
76
+ });
38
77
  }
39
78
 
40
79
  /**
41
- * The above function sets the value of the "start" property.
42
- * @param {number} value - The value parameter is of type number.
80
+ * Create a min segment tree.
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+ * @example
114
+ * // Temperature monitoring with range queries
115
+ * // Hourly temperatures for a day (24 readings)
116
+ * const temps = [18, 17, 16, 15, 16, 18, 21, 24, 27, 29, 31, 32, 33, 32, 31, 29, 27, 25, 23, 21, 20, 19, 18, 17];
117
+ * const tree = SegmentTree.sum(temps);
118
+ *
119
+ * // Average temperature during work hours (9-17)
120
+ * const workSum = tree.query(9, 17);
121
+ * console.log(workSum / 9); // toBeCloseTo;
122
+ *
123
+ * // Sum of morning temps (6-11)
124
+ * console.log(tree.query(6, 11)); // 164;
43
125
  */
44
- set start(value: number) {
45
- this._start = value;
126
+ static min(elements: number[]): SegmentTree<number> {
127
+ return new SegmentTree<number>(elements, {
128
+ merger: (a, b) => Math.min(a, b),
129
+ identity: Infinity
130
+ });
46
131
  }
47
132
 
48
- protected _end = 0;
49
-
50
133
  /**
51
- * The function returns the value of the protected variable `_end`.
52
- * @returns The value of the protected property `_end`.
134
+ * Create a max segment tree.
135
+ * @example
136
+ * ```ts
137
+ * const st = SegmentTree.max([3, 1, 4, 1, 5]);
138
+ * st.query(1, 4); // 5
139
+ * ```
53
140
  */
54
- get end(): number {
55
- return this._end;
141
+ static max(elements: number[]): SegmentTree<number> {
142
+ return new SegmentTree<number>(elements, {
143
+ merger: (a, b) => Math.max(a, b),
144
+ identity: -Infinity
145
+ });
56
146
  }
57
147
 
148
+ // ─── Core operations ───────────────────────────────────────
149
+
58
150
  /**
59
- * The above function sets the value of the "end" property.
60
- * @param {number} value - The value parameter is a number that represents the new value for the end
61
- * property.
151
+ * Point update: set element at index to value.
152
+ * Time: O(log n)
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+
165
+
166
+
167
+
168
+
169
+
170
+
171
+
172
+
173
+
174
+
175
+
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+ * @example
186
+ * // Dynamic range sum with updates
187
+ * // Monthly revenue data (in thousands)
188
+ * const revenue = [120, 95, 140, 110, 85, 130, 150, 100, 160, 125, 90, 175];
189
+ * const tree = SegmentTree.sum(revenue);
190
+ *
191
+ * // Q1 revenue (Jan-Mar)
192
+ * console.log(tree.query(0, 2)); // 355;
193
+ *
194
+ * // Update March revenue from 140 to 200
195
+ * tree.update(2, 200);
196
+ *
197
+ * // Q1 revenue after update
198
+ * console.log(tree.query(0, 2)); // 415;
199
+ *
200
+ * // H1 revenue (Jan-Jun)
201
+ * console.log(tree.query(0, 5)); // 740;
62
202
  */
63
- set end(value: number) {
64
- this._end = value;
65
- }
203
+ update(index: number, value: E): void {
204
+ if (index < 0 || index >= this._n) return;
66
205
 
67
- protected _value: SegmentTreeNodeVal | undefined = undefined;
206
+ let pos = this._treeSize + index;
207
+ this._tree[pos] = value;
68
208
 
69
- /**
70
- * The function returns the value of a segment tree node.
71
- * @returns The value being returned is either a `SegmentTreeNodeVal` object or `undefined`.
72
- */
73
- get value(): SegmentTreeNodeVal | undefined {
74
- return this._value;
209
+ // Propagate up
210
+ pos >>= 1;
211
+ while (pos >= 1) {
212
+ this._tree[pos] = this._merger(this._tree[2 * pos], this._tree[2 * pos + 1]);
213
+ pos >>= 1;
214
+ }
75
215
  }
76
216
 
77
217
  /**
78
- * The function sets the value of a segment tree node.
79
- * @param {SegmentTreeNodeVal | undefined} value - The `value` parameter is of type
80
- * `SegmentTreeNodeVal` or `undefined`.
218
+ * Range query: returns merger result over [start, end] (inclusive).
219
+ * Time: O(log n)
220
+
221
+
222
+
223
+
224
+
225
+
226
+
227
+
228
+
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+
237
+
238
+
239
+
240
+
241
+
242
+
243
+
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+ * @example
253
+ * // Range sum query on an array
254
+ * const tree = SegmentTree.sum([1, 3, 5, 7, 9, 11]);
255
+ *
256
+ * // Query sum of range [1, 3] → 3 + 5 + 7 = 15
257
+ * console.log(tree.query(1, 3)); // 15;
258
+ *
259
+ * // Query entire range
260
+ * console.log(tree.query(0, 5)); // 36;
261
+ *
262
+ * // Query single element
263
+ * console.log(tree.query(2, 2)); // 5;
81
264
  */
82
- set value(value: SegmentTreeNodeVal | undefined) {
83
- this._value = value;
84
- }
85
-
86
- protected _sum = 0;
265
+ query(start: number, end: number): E {
266
+ if (start < 0) start = 0;
267
+ if (end >= this._n) end = this._n - 1;
268
+ if (start > end) return this._identity;
269
+
270
+ let resultLeft = this._identity;
271
+ let resultRight = this._identity;
272
+ let left = this._treeSize + start;
273
+ let right = this._treeSize + end + 1; // exclusive
274
+
275
+ while (left < right) {
276
+ if (left & 1) {
277
+ resultLeft = this._merger(resultLeft, this._tree[left]);
278
+ left++;
279
+ }
280
+ if (right & 1) {
281
+ right--;
282
+ resultRight = this._merger(this._tree[right], resultRight);
283
+ }
284
+ left >>= 1;
285
+ right >>= 1;
286
+ }
87
287
 
88
- /**
89
- * The function returns the value of the sum property.
90
- * @returns The method is returning the value of the variable `_sum`.
91
- */
92
- get sum(): number {
93
- return this._sum;
288
+ return this._merger(resultLeft, resultRight);
94
289
  }
95
290
 
96
291
  /**
97
- * The above function sets the value of the sum property.
98
- * @param {number} value - The parameter "value" is of type "number".
292
+ * Get element at index.
293
+ * Time: O(1)
294
+
295
+
296
+
297
+
298
+
299
+
300
+
301
+
302
+
303
+
304
+
305
+
306
+
307
+
308
+
309
+
310
+
311
+
312
+
313
+
314
+
315
+
316
+
317
+
318
+
319
+
320
+
321
+
322
+
323
+
324
+
325
+
326
+ * @example
327
+ * // Point access on segment tree
328
+ * const st = SegmentTree.sum([10, 20, 30, 40]);
329
+ * console.log(st.get(0)); // 10;
330
+ * console.log(st.get(2)); // 30;
99
331
  */
100
- set sum(value: number) {
101
- this._sum = value;
332
+ get(index: number): E {
333
+ if (index < 0 || index >= this._n) return this._identity;
334
+ return this._tree[this._treeSize + index];
102
335
  }
103
336
 
104
- protected _left: SegmentTreeNode | undefined = undefined;
337
+ // ─── Binary search on tree (ACL-style) ─────────────────────
105
338
 
106
339
  /**
107
- * The function returns the left child of a segment tree node.
108
- * @returns The `left` property of the `SegmentTreeNode` object is being returned. It is of type
109
- * `SegmentTreeNode` or `undefined`.
340
+ * Find the largest r such that predicate(query(left, r)) is true.
341
+ * Returns left-1 if predicate(identity) is false.
342
+ * Returns n-1 if predicate holds for the entire range [left, n-1].
343
+ * Time: O(log n)
344
+
345
+
346
+
347
+
348
+
349
+
350
+
351
+
352
+
353
+
354
+
355
+
356
+
357
+
358
+
359
+
360
+
361
+
362
+
363
+
364
+
365
+
366
+
367
+
368
+
369
+
370
+
371
+
372
+
373
+
374
+
375
+
376
+ * @example
377
+ * // Find rightmost position where predicate holds
378
+ * // Prefix sums: find the rightmost index where prefix sum < 10
379
+ * const st = SegmentTree.sum([3, 1, 4, 1, 5]);
380
+ * // maxRight(0, sum => sum < 10) — prefix [3,4,8,9,14]
381
+ * // sum < 10 holds through index 3 (prefix=9), fails at 4 (prefix=14)
382
+ * const result = st.maxRight(0, sum => sum < 10);
383
+ * console.log(result); // 3;
110
384
  */
111
- get left(): SegmentTreeNode | undefined {
112
- return this._left;
113
- }
385
+ maxRight(left: number, predicate: (segValue: E) => boolean): number {
386
+ if (left >= this._n) return this._n - 1;
387
+
388
+ let acc = this._identity;
389
+ if (!predicate(acc)) return left - 1;
390
+
391
+ let pos = this._treeSize + left;
392
+
393
+ // Go up while we're a right child or predicate still holds
394
+ while (true) {
395
+ // Find the lowest relevant node
396
+ while (pos < this._treeSize) {
397
+ // Try going left
398
+ const combined = this._merger(acc, this._tree[2 * pos]);
399
+ if (predicate(combined)) {
400
+ acc = combined;
401
+ pos = 2 * pos + 1; // go right
402
+ } else {
403
+ pos = 2 * pos; // go left (dig deeper)
404
+ }
405
+ }
114
406
 
115
- /**
116
- * The function sets the value of the left property of a SegmentTreeNode object.
117
- * @param {SegmentTreeNode | undefined} value - The value parameter is of type SegmentTreeNode or
118
- * undefined.
119
- */
120
- set left(value: SegmentTreeNode | undefined) {
121
- this._left = value;
122
- }
407
+ // At leaf level
408
+ const combined = this._merger(acc, this._tree[pos]);
409
+ if (!predicate(combined)) {
410
+ return pos - this._treeSize - 1;
411
+ }
412
+ acc = combined;
123
413
 
124
- protected _right: SegmentTreeNode | undefined = undefined;
414
+ // Move to next segment
415
+ pos++;
416
+ // Check if we've gone past the end
417
+ if (pos - this._treeSize >= this._n) return this._n - 1;
125
418
 
126
- /**
127
- * The function returns the right child of a segment tree node.
128
- * @returns The `getRight()` method is returning a value of type `SegmentTreeNode` or `undefined`.
129
- */
130
- get right(): SegmentTreeNode | undefined {
131
- return this._right;
419
+ // Go up while we're a right child
420
+ while (pos > 1 && (pos & 1) === 0) {
421
+ pos >>= 1;
422
+ }
423
+ /* istanbul ignore next -- defensive: pos===1 unreachable when _n < _treeSize guard above catches exit */
424
+ if (pos === 1) return this._n - 1;
425
+ }
132
426
  }
133
427
 
134
428
  /**
135
- * The function sets the right child of a segment tree node.
136
- * @param {SegmentTreeNode | undefined} value - The `value` parameter is of type `SegmentTreeNode |
137
- * undefined`. This means that it can accept either a `SegmentTreeNode` object or `undefined` as its
138
- * value.
429
+ * Find the smallest l such that predicate(query(l, right)) is true.
430
+ * Returns right+1 if predicate(identity) is false.
431
+ * Returns 0 if predicate holds for the entire range [0, right].
432
+ * Time: O(log n)
433
+
434
+
435
+
436
+
437
+
438
+
439
+
440
+
441
+
442
+
443
+
444
+
445
+
446
+
447
+
448
+
449
+
450
+
451
+
452
+
453
+
454
+
455
+
456
+
457
+
458
+
459
+
460
+
461
+
462
+
463
+
464
+
465
+ * @example
466
+ * // Find leftmost position where predicate holds
467
+ * const st = SegmentTree.sum([3, 1, 4, 1, 5]);
468
+ * // minLeft(5, sum => sum < 7) — suffix sums from right
469
+ * // From right: [5]=5 < 7, [1,5]=6 < 7, [4,1,5]=10 ≥ 7
470
+ * const result = st.minLeft(5, sum => sum < 7);
471
+ * console.log(result); // 3;
139
472
  */
140
- set right(value: SegmentTreeNode | undefined) {
141
- this._right = value;
142
- }
143
- }
473
+ minLeft(right: number, predicate: (segValue: E) => boolean): number {
474
+ if (right < 0) return 0;
475
+ if (right >= this._n) right = this._n - 1;
144
476
 
145
- export class SegmentTree {
146
- /**
147
- * The constructor initializes the values, start, end, and root properties of an object.
148
- * @param {number[]} values - An array of numbers that will be used to build a binary search tree.
149
- * @param {number} [start] - The `start` parameter is the index of the first element in the `values` array that should
150
- * be included in the range. If no value is provided for `start`, it defaults to 0, which means the range starts from
151
- * the beginning of the array.
152
- * @param {number} [end] - The "end" parameter is the index of the last element in the "values" array that should be
153
- * included in the range. If not provided, it defaults to the index of the last element in the "values" array.
154
- */
155
- constructor(values: number[], start?: number, end?: number) {
156
- start = start || 0;
157
- end = end || values.length - 1;
158
- this._values = values;
159
- this._start = start;
160
- this._end = end;
161
-
162
- if (values.length > 0) {
163
- this._root = this.build(start, end);
164
- } else {
165
- this._root = undefined;
166
- this._values = [];
167
- }
168
- }
477
+ let acc = this._identity;
478
+ if (!predicate(acc)) return right + 1;
169
479
 
170
- protected _values: number[] = [];
480
+ let pos = this._treeSize + right;
171
481
 
172
- /**
173
- * The function returns an array of numbers.
174
- * @returns An array of numbers is being returned.
175
- */
176
- get values(): number[] {
177
- return this._values;
178
- }
482
+ while (true) {
483
+ while (pos < this._treeSize) {
484
+ const combined = this._merger(this._tree[2 * pos + 1], acc);
485
+ if (predicate(combined)) {
486
+ acc = combined;
487
+ pos = 2 * pos; // go left
488
+ } else {
489
+ pos = 2 * pos + 1; // go right (dig deeper)
490
+ }
491
+ }
179
492
 
180
- protected _start = 0;
493
+ const combined = this._merger(this._tree[pos], acc);
494
+ if (!predicate(combined)) {
495
+ return pos - this._treeSize + 1;
496
+ }
497
+ acc = combined;
181
498
 
182
- /**
183
- * The function returns the value of the protected variable _start.
184
- * @returns The start value, which is of type number.
185
- */
186
- get start(): number {
187
- return this._start;
499
+ // Move to previous segment
500
+ if (pos === this._treeSize) return 0;
501
+ pos--;
502
+
503
+ // Go up while we're a left child
504
+ while (pos > 1 && (pos & 1) === 1) {
505
+ pos >>= 1;
506
+ }
507
+ /* istanbul ignore next -- defensive: pos===1 unreachable when _treeSize guard above catches exit */
508
+ if (pos === 1) return 0;
509
+ }
188
510
  }
189
511
 
190
- protected _end: number;
512
+ // ─── Standard interface ────────────────────────────────────
191
513
 
192
- /**
193
- * The function returns the value of the protected variable `_end`.
194
- * @returns The value of the protected property `_end`.
195
- */
196
- get end(): number {
197
- return this._end;
514
+ get size(): number {
515
+ return this._n;
198
516
  }
199
517
 
200
- protected _root: SegmentTreeNode | undefined;
518
+ isEmpty(): boolean {
519
+ return this._n === 0;
520
+ }
201
521
 
202
- /**
203
- * The function returns the root node of a segment tree.
204
- * @returns The `root` property of the class `SegmentTreeNode` or `undefined` if it is not defined.
205
- */
206
- get root(): SegmentTreeNode | undefined {
207
- return this._root;
522
+ clone(): SegmentTree<E> {
523
+ const elements: E[] = [];
524
+ for (let i = 0; i < this._n; i++) {
525
+ elements.push(this._tree[this._treeSize + i]);
526
+ }
527
+ return new SegmentTree<E>(elements, {
528
+ merger: this._merger,
529
+ identity: this._identity
530
+ });
208
531
  }
209
532
 
210
- /**
211
- * The build function creates a segment tree by recursively dividing the given range into smaller segments and assigning
212
- * the sum of values to each segment.
213
- * @param {number} start - The `start` parameter represents the starting index of the segment or range for which we are
214
- * building the segment tree.
215
- * @param {number} end - The "end" parameter represents the ending index of the segment or range for which we want to
216
- * build a segment tree.
217
- * @returns a SegmentTreeNode object.
218
- */
219
- build(start: number, end: number): SegmentTreeNode {
220
- if (start > end) {
221
- return new SegmentTreeNode(start, end, 0);
533
+ toArray(): E[] {
534
+ const result: E[] = [];
535
+ for (let i = 0; i < this._n; i++) {
536
+ result.push(this._tree[this._treeSize + i]);
222
537
  }
223
- if (start === end) return new SegmentTreeNode(start, end, this._values[start]);
224
-
225
- const mid = start + Math.floor((end - start) / 2);
226
- const left = this.build(start, mid);
227
- const right = this.build(mid + 1, end);
228
- const cur = new SegmentTreeNode(start, end, left.sum + right.sum);
229
- cur.left = left;
230
- cur.right = right;
231
- return cur;
538
+ return result;
232
539
  }
233
540
 
234
541
  /**
235
- * The function updates the value of a node in a segment tree and recalculates the sum of its children if they exist.
236
- * @param {number} index - The index parameter represents the index of the node in the segment tree that needs to be
237
- * updated.
238
- * @param {number} sum - The `sum` parameter represents the new value that should be assigned to the `sum` property of
239
- * the `SegmentTreeNode` at the specified `index`.
240
- * @param {SegmentTreeNodeVal} [value] - The `value` parameter is an optional value that can be assigned to the `value`
241
- * property of the `SegmentTreeNode` object. It is not currently used in the code, but you can uncomment the line `//
242
- * cur.value = value;` and pass a value for `value` in the
243
- * @returns The function does not return anything.
542
+ * Iterates over leaf values in index order.
244
543
  */
245
- updateNode(index: number, sum: number, value?: SegmentTreeNodeVal) {
246
- const root = this.root || undefined;
247
- if (!root) {
248
- return;
249
- }
250
- const dfs = (cur: SegmentTreeNode, index: number, sum: number, value?: SegmentTreeNodeVal) => {
251
- if (cur.start === cur.end && cur.start === index) {
252
- cur.sum = sum;
253
- if (value !== undefined) cur.value = value;
254
- return;
255
- }
256
- const mid = cur.start + Math.floor((cur.end - cur.start) / 2);
257
- if (index <= mid) {
258
- if (cur.left) {
259
- dfs(cur.left, index, sum, value);
544
+ [Symbol.iterator](): IterableIterator<E> {
545
+ const tree = this._tree;
546
+ const treeSize = this._treeSize;
547
+ const n = this._n;
548
+ let i = 0;
549
+ return {
550
+ [Symbol.iterator]() {
551
+ return this;
552
+ },
553
+ next(): IteratorResult<E> {
554
+ if (i < n) {
555
+ return { value: tree[treeSize + i++], done: false };
260
556
  }
261
- } else {
262
- if (cur.right) {
263
- dfs(cur.right, index, sum, value);
264
- }
265
- }
266
- if (cur.left && cur.right) {
267
- cur.sum = cur.left.sum + cur.right.sum;
557
+ return { value: undefined, done: true } as IteratorResult<E>;
268
558
  }
269
559
  };
270
-
271
- dfs(root, index, sum, value);
272
560
  }
273
561
 
274
- /**
275
- * The function `querySumByRange` calculates the sum of values within a given range in a segment tree.
276
- * @param {number} indexA - The starting index of the range for which you want to calculate the sum.
277
- * @param {number} indexB - The parameter `indexB` represents the ending index of the range for which you want to
278
- * calculate the sum.
279
- * @returns The function `querySumByRange` returns a number.
280
- */
281
- querySumByRange(indexA: number, indexB: number): number {
282
- const root = this.root || undefined;
283
- if (!root) {
284
- return 0;
285
- }
286
-
287
- if (indexA < 0 || indexB >= this.values.length || indexA > indexB) {
288
- return NaN;
562
+ forEach(callback: (value: E, index: number) => void): void {
563
+ for (let i = 0; i < this._n; i++) {
564
+ callback(this._tree[this._treeSize + i], i);
289
565
  }
566
+ }
290
567
 
291
- const dfs = (cur: SegmentTreeNode, i: number, j: number): number => {
292
- if (i <= cur.start && j >= cur.end) {
293
- // The range [i, j] completely covers the current node's range [cur.start, cur.end]
294
- return cur.sum;
295
- }
296
- const mid = cur.start + Math.floor((cur.end - cur.start) / 2);
297
- if (j <= mid) {
298
- if (cur.left) {
299
- return dfs(cur.left, i, j);
300
- } else {
301
- return NaN;
302
- }
303
- } else if (i > mid) {
304
- if (cur.right) {
305
- return dfs(cur.right, i, j);
306
- } else {
307
- return NaN;
308
- }
309
- } else {
310
- // Query both left and right subtrees
311
- let leftSum = 0;
312
- let rightSum = 0;
313
- if (cur.left) {
314
- leftSum = dfs(cur.left, i, mid);
315
- }
316
- if (cur.right) {
317
- rightSum = dfs(cur.right, mid + 1, j);
318
- }
319
- return leftSum + rightSum;
320
- }
321
- };
322
- return dfs(root, indexA, indexB);
568
+ print(): void {
569
+ console.log(this.toArray());
323
570
  }
324
571
  }
572
+
573
+