data-structure-typed 2.6.0 → 2.6.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.
- package/.github/workflows/ci.yml +7 -2
- package/.github/workflows/release-package.yml +9 -2
- package/docs-site-docusaurus/docs/api/classes/AVLTree.md +108 -108
- package/docs-site-docusaurus/docs/api/classes/BST.md +101 -101
- package/docs-site-docusaurus/docs/api/classes/BinaryIndexedTree.md +13 -13
- package/docs-site-docusaurus/docs/api/classes/BinaryTree.md +66 -66
- package/docs-site-docusaurus/docs/api/classes/Deque.md +235 -51
- package/docs-site-docusaurus/docs/api/classes/DirectedGraph.md +21 -21
- package/docs-site-docusaurus/docs/api/classes/DoublyLinkedList.md +231 -67
- package/docs-site-docusaurus/docs/api/classes/FibonacciHeap.md +9 -9
- package/docs-site-docusaurus/docs/api/classes/FibonacciHeapNode.md +1 -1
- package/docs-site-docusaurus/docs/api/classes/HashMap.md +14 -14
- package/docs-site-docusaurus/docs/api/classes/Heap.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/IterableElementBase.md +83 -13
- package/docs-site-docusaurus/docs/api/classes/LinearBase.md +124 -20
- package/docs-site-docusaurus/docs/api/classes/LinearLinkedBase.md +140 -32
- package/docs-site-docusaurus/docs/api/classes/LinkedHashMap.md +23 -23
- package/docs-site-docusaurus/docs/api/classes/LinkedListQueue.md +159 -51
- package/docs-site-docusaurus/docs/api/classes/MapGraph.md +20 -20
- package/docs-site-docusaurus/docs/api/classes/Matrix.md +23 -23
- package/docs-site-docusaurus/docs/api/classes/MaxHeap.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/MaxPriorityQueue.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/MinHeap.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/MinPriorityQueue.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/PriorityQueue.md +117 -34
- package/docs-site-docusaurus/docs/api/classes/Queue.md +142 -34
- package/docs-site-docusaurus/docs/api/classes/RedBlackTree.md +117 -117
- package/docs-site-docusaurus/docs/api/classes/SegmentTree.md +8 -8
- package/docs-site-docusaurus/docs/api/classes/SinglyLinkedList.md +158 -50
- package/docs-site-docusaurus/docs/api/classes/SkipList.md +21 -21
- package/docs-site-docusaurus/docs/api/classes/Stack.md +108 -26
- package/docs-site-docusaurus/docs/api/classes/TreeMap.md +33 -33
- package/docs-site-docusaurus/docs/api/classes/TreeMultiMap.md +75 -39
- package/docs-site-docusaurus/docs/api/classes/TreeSet.md +301 -39
- package/docs-site-docusaurus/docs/api/classes/Trie.md +110 -28
- package/docs-site-docusaurus/docs/api/classes/UndirectedGraph.md +20 -20
- package/package.json +45 -46
- package/src/common/error.ts +15 -32
- package/src/common/index.ts +0 -3
- package/src/data-structures/base/iterable-element-base.ts +0 -3
- package/src/data-structures/base/linear-base.ts +2 -36
- package/src/data-structures/binary-tree/avl-tree.ts +31 -529
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +47 -572
- package/src/data-structures/binary-tree/binary-tree.ts +326 -1311
- package/src/data-structures/binary-tree/bst.ts +158 -1082
- package/src/data-structures/binary-tree/red-black-tree.ts +451 -1290
- package/src/data-structures/binary-tree/segment-tree.ts +73 -351
- package/src/data-structures/binary-tree/tree-map.ts +462 -5124
- package/src/data-structures/binary-tree/tree-multi-map.ts +302 -4914
- package/src/data-structures/binary-tree/tree-multi-set.ts +284 -3972
- package/src/data-structures/binary-tree/tree-set.ts +338 -4836
- package/src/data-structures/graph/abstract-graph.ts +98 -167
- package/src/data-structures/graph/directed-graph.ts +137 -562
- package/src/data-structures/graph/map-graph.ts +0 -3
- package/src/data-structures/graph/undirected-graph.ts +132 -511
- package/src/data-structures/hash/hash-map.ts +154 -582
- package/src/data-structures/heap/heap.ts +200 -795
- package/src/data-structures/linked-list/doubly-linked-list.ts +121 -865
- package/src/data-structures/linked-list/singly-linked-list.ts +122 -794
- package/src/data-structures/linked-list/skip-linked-list.ts +211 -918
- package/src/data-structures/matrix/matrix.ts +179 -518
- package/src/data-structures/matrix/navigator.ts +0 -1
- package/src/data-structures/priority-queue/max-priority-queue.ts +1 -6
- package/src/data-structures/priority-queue/min-priority-queue.ts +6 -11
- package/src/data-structures/priority-queue/priority-queue.ts +1 -2
- package/src/data-structures/queue/deque.ts +214 -882
- package/src/data-structures/queue/queue.ts +102 -625
- package/src/data-structures/stack/stack.ts +76 -505
- package/src/data-structures/trie/trie.ts +98 -628
- package/src/types/common.ts +0 -10
- package/src/types/data-structures/binary-tree/bst.ts +0 -7
- package/src/types/data-structures/binary-tree/red-black-tree.ts +0 -1
- package/src/types/data-structures/graph/abstract-graph.ts +0 -2
- package/src/types/data-structures/hash/hash-map.ts +0 -3
- package/src/types/data-structures/hash/index.ts +0 -1
- package/src/types/data-structures/matrix/navigator.ts +0 -2
- package/src/types/utils/utils.ts +0 -7
- package/src/types/utils/validate-type.ts +0 -7
- package/src/utils/number.ts +0 -2
- package/src/utils/utils.ts +0 -5
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* @author Pablo Zeng
|
|
5
5
|
* @license MIT License
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
7
|
export type SegmentTreeOptions<E> = {
|
|
9
8
|
merger: (a: E, b: E) => E;
|
|
10
9
|
identity: E;
|
|
@@ -30,27 +29,22 @@ export type SegmentTreeOptions<E> = {
|
|
|
30
29
|
export class SegmentTree<E = number> implements Iterable<E> {
|
|
31
30
|
protected readonly _merger: (a: E, b: E) => E;
|
|
32
31
|
protected readonly _identity: E;
|
|
33
|
-
protected _n: number;
|
|
34
|
-
protected _tree: E[];
|
|
35
|
-
protected _treeSize: number;
|
|
36
|
-
|
|
32
|
+
protected _n: number; // number of leaf elements
|
|
33
|
+
protected _tree: E[]; // flat array, 1-indexed, size 2*_size
|
|
34
|
+
protected _treeSize: number; // internal tree size (next power of 2 >= _n)
|
|
37
35
|
constructor(elements: E[], options: SegmentTreeOptions<E>) {
|
|
38
36
|
this._merger = options.merger;
|
|
39
37
|
this._identity = options.identity;
|
|
40
38
|
this._n = elements.length;
|
|
41
|
-
|
|
42
39
|
// Round up to next power of 2
|
|
43
40
|
this._treeSize = 1;
|
|
44
41
|
while (this._treeSize < this._n) this._treeSize <<= 1;
|
|
45
|
-
|
|
46
42
|
// Allocate and fill with identity
|
|
47
43
|
this._tree = new Array(2 * this._treeSize).fill(this._identity);
|
|
48
|
-
|
|
49
44
|
// Place elements in leaves
|
|
50
45
|
for (let i = 0; i < this._n; i++) {
|
|
51
46
|
this._tree[this._treeSize + i] = elements[i];
|
|
52
47
|
}
|
|
53
|
-
|
|
54
48
|
// Build internal nodes bottom-up
|
|
55
49
|
for (let i = this._treeSize - 1; i >= 1; i--) {
|
|
56
50
|
this._tree[i] = this._merger(this._tree[2 * i], this._tree[2 * i + 1]);
|
|
@@ -59,6 +53,11 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
59
53
|
|
|
60
54
|
// ─── Convenience factories ─────────────────────────────────
|
|
61
55
|
|
|
56
|
+
// ─── Standard interface ────────────────────────────────────
|
|
57
|
+
get size(): number {
|
|
58
|
+
return this._n;
|
|
59
|
+
}
|
|
60
|
+
|
|
62
61
|
/**
|
|
63
62
|
* Create a sum segment tree.
|
|
64
63
|
* @example
|
|
@@ -78,60 +77,18 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
78
77
|
|
|
79
78
|
/**
|
|
80
79
|
* 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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
* @example
|
|
124
|
-
* // Temperature monitoring with range queries
|
|
125
|
-
* // Hourly temperatures for a day (24 readings)
|
|
126
|
-
* 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];
|
|
127
|
-
* const tree = SegmentTree.sum(temps);
|
|
128
|
-
*
|
|
129
|
-
* // Average temperature during work hours (9-17)
|
|
130
|
-
* const workSum = tree.query(9, 17);
|
|
131
|
-
* console.log(workSum / 9); // toBeCloseTo;
|
|
132
|
-
*
|
|
133
|
-
* // Sum of morning temps (6-11)
|
|
134
|
-
* console.log(tree.query(6, 11)); // 164;
|
|
80
|
+
* @example
|
|
81
|
+
* // Temperature monitoring with range queries
|
|
82
|
+
* // Hourly temperatures for a day (24 readings)
|
|
83
|
+
* 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];
|
|
84
|
+
* const tree = SegmentTree.sum(temps);
|
|
85
|
+
*
|
|
86
|
+
* // Average temperature during work hours (9-17)
|
|
87
|
+
* const workSum = tree.query(9, 17);
|
|
88
|
+
* console.log(workSum / 9); // toBeCloseTo;
|
|
89
|
+
*
|
|
90
|
+
* // Sum of morning temps (6-11)
|
|
91
|
+
* console.log(tree.query(6, 11)); // 164;
|
|
135
92
|
*/
|
|
136
93
|
static min(elements: number[]): SegmentTree<number> {
|
|
137
94
|
return new SegmentTree<number>(elements, {
|
|
@@ -140,6 +97,8 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
140
97
|
});
|
|
141
98
|
}
|
|
142
99
|
|
|
100
|
+
// ─── Core operations ───────────────────────────────────────
|
|
101
|
+
|
|
143
102
|
/**
|
|
144
103
|
* Create a max segment tree.
|
|
145
104
|
* @example
|
|
@@ -155,77 +114,31 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
155
114
|
});
|
|
156
115
|
}
|
|
157
116
|
|
|
158
|
-
// ─── Core operations ───────────────────────────────────────
|
|
159
|
-
|
|
160
117
|
/**
|
|
161
118
|
* Point update: set element at index to value.
|
|
162
119
|
* Time: O(log n)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
* @example
|
|
206
|
-
* // Dynamic range sum with updates
|
|
207
|
-
* // Monthly revenue data (in thousands)
|
|
208
|
-
* const revenue = [120, 95, 140, 110, 85, 130, 150, 100, 160, 125, 90, 175];
|
|
209
|
-
* const tree = SegmentTree.sum(revenue);
|
|
210
|
-
*
|
|
211
|
-
* // Q1 revenue (Jan-Mar)
|
|
212
|
-
* console.log(tree.query(0, 2)); // 355;
|
|
213
|
-
*
|
|
214
|
-
* // Update March revenue from 140 to 200
|
|
215
|
-
* tree.update(2, 200);
|
|
216
|
-
*
|
|
217
|
-
* // Q1 revenue after update
|
|
218
|
-
* console.log(tree.query(0, 2)); // 415;
|
|
219
|
-
*
|
|
220
|
-
* // H1 revenue (Jan-Jun)
|
|
221
|
-
* console.log(tree.query(0, 5)); // 740;
|
|
120
|
+
* @example
|
|
121
|
+
* // Dynamic range sum with updates
|
|
122
|
+
* // Monthly revenue data (in thousands)
|
|
123
|
+
* const revenue = [120, 95, 140, 110, 85, 130, 150, 100, 160, 125, 90, 175];
|
|
124
|
+
* const tree = SegmentTree.sum(revenue);
|
|
125
|
+
*
|
|
126
|
+
* // Q1 revenue (Jan-Mar)
|
|
127
|
+
* console.log(tree.query(0, 2)); // 355;
|
|
128
|
+
*
|
|
129
|
+
* // Update March revenue from 140 to 200
|
|
130
|
+
* tree.update(2, 200);
|
|
131
|
+
*
|
|
132
|
+
* // Q1 revenue after update
|
|
133
|
+
* console.log(tree.query(0, 2)); // 415;
|
|
134
|
+
*
|
|
135
|
+
* // H1 revenue (Jan-Jun)
|
|
136
|
+
* console.log(tree.query(0, 5)); // 740;
|
|
222
137
|
*/
|
|
223
138
|
update(index: number, value: E): void {
|
|
224
139
|
if (index < 0 || index >= this._n) return;
|
|
225
|
-
|
|
226
140
|
let pos = this._treeSize + index;
|
|
227
141
|
this._tree[pos] = value;
|
|
228
|
-
|
|
229
142
|
// Propagate up
|
|
230
143
|
pos >>= 1;
|
|
231
144
|
while (pos >= 1) {
|
|
@@ -237,71 +150,27 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
237
150
|
/**
|
|
238
151
|
* Range query: returns merger result over [start, end] (inclusive).
|
|
239
152
|
* Time: O(log n)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
* @example
|
|
283
|
-
* // Range sum query on an array
|
|
284
|
-
* const tree = SegmentTree.sum([1, 3, 5, 7, 9, 11]);
|
|
285
|
-
*
|
|
286
|
-
* // Query sum of range [1, 3] → 3 + 5 + 7 = 15
|
|
287
|
-
* console.log(tree.query(1, 3)); // 15;
|
|
288
|
-
*
|
|
289
|
-
* // Query entire range
|
|
290
|
-
* console.log(tree.query(0, 5)); // 36;
|
|
291
|
-
*
|
|
292
|
-
* // Query single element
|
|
293
|
-
* console.log(tree.query(2, 2)); // 5;
|
|
153
|
+
* @example
|
|
154
|
+
* // Range sum query on an array
|
|
155
|
+
* const tree = SegmentTree.sum([1, 3, 5, 7, 9, 11]);
|
|
156
|
+
*
|
|
157
|
+
* // Query sum of range [1, 3] → 3 + 5 + 7 = 15
|
|
158
|
+
* console.log(tree.query(1, 3)); // 15;
|
|
159
|
+
*
|
|
160
|
+
* // Query entire range
|
|
161
|
+
* console.log(tree.query(0, 5)); // 36;
|
|
162
|
+
*
|
|
163
|
+
* // Query single element
|
|
164
|
+
* console.log(tree.query(2, 2)); // 5;
|
|
294
165
|
*/
|
|
295
166
|
query(start: number, end: number): E {
|
|
296
167
|
if (start < 0) start = 0;
|
|
297
168
|
if (end >= this._n) end = this._n - 1;
|
|
298
169
|
if (start > end) return this._identity;
|
|
299
|
-
|
|
300
170
|
let resultLeft = this._identity;
|
|
301
171
|
let resultRight = this._identity;
|
|
302
172
|
let left = this._treeSize + start;
|
|
303
173
|
let right = this._treeSize + end + 1; // exclusive
|
|
304
|
-
|
|
305
174
|
while (left < right) {
|
|
306
175
|
if (left & 1) {
|
|
307
176
|
resultLeft = this._merger(resultLeft, this._tree[left]);
|
|
@@ -314,132 +183,44 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
314
183
|
left >>= 1;
|
|
315
184
|
right >>= 1;
|
|
316
185
|
}
|
|
317
|
-
|
|
318
186
|
return this._merger(resultLeft, resultRight);
|
|
319
187
|
}
|
|
320
188
|
|
|
189
|
+
// ─── Binary search on tree (ACL-style) ─────────────────────
|
|
190
|
+
|
|
321
191
|
/**
|
|
322
192
|
* Get element at index.
|
|
323
193
|
* Time: O(1)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
* @example
|
|
367
|
-
* // Point access on segment tree
|
|
368
|
-
* const st = SegmentTree.sum([10, 20, 30, 40]);
|
|
369
|
-
* console.log(st.get(0)); // 10;
|
|
370
|
-
* console.log(st.get(2)); // 30;
|
|
194
|
+
* @example
|
|
195
|
+
* // Point access on segment tree
|
|
196
|
+
* const st = SegmentTree.sum([10, 20, 30, 40]);
|
|
197
|
+
* console.log(st.get(0)); // 10;
|
|
198
|
+
* console.log(st.get(2)); // 30;
|
|
371
199
|
*/
|
|
372
200
|
get(index: number): E {
|
|
373
201
|
if (index < 0 || index >= this._n) return this._identity;
|
|
374
202
|
return this._tree[this._treeSize + index];
|
|
375
203
|
}
|
|
376
204
|
|
|
377
|
-
// ─── Binary search on tree (ACL-style) ─────────────────────
|
|
378
|
-
|
|
379
205
|
/**
|
|
380
206
|
* Find the largest r such that predicate(query(left, r)) is true.
|
|
381
207
|
* Returns left-1 if predicate(identity) is false.
|
|
382
208
|
* Returns n-1 if predicate holds for the entire range [left, n-1].
|
|
383
209
|
* Time: O(log n)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
* @example
|
|
427
|
-
* // Find rightmost position where predicate holds
|
|
428
|
-
* // Prefix sums: find the rightmost index where prefix sum < 10
|
|
429
|
-
* const st = SegmentTree.sum([3, 1, 4, 1, 5]);
|
|
430
|
-
* // maxRight(0, sum => sum < 10) — prefix [3,4,8,9,14]
|
|
431
|
-
* // sum < 10 holds through index 3 (prefix=9), fails at 4 (prefix=14)
|
|
432
|
-
* const result = st.maxRight(0, sum => sum < 10);
|
|
433
|
-
* console.log(result); // 3;
|
|
210
|
+
* @example
|
|
211
|
+
* // Find rightmost position where predicate holds
|
|
212
|
+
* // Prefix sums: find the rightmost index where prefix sum < 10
|
|
213
|
+
* const st = SegmentTree.sum([3, 1, 4, 1, 5]);
|
|
214
|
+
* // maxRight(0, sum => sum < 10) — prefix [3,4,8,9,14]
|
|
215
|
+
* // sum < 10 holds through index 3 (prefix=9), fails at 4 (prefix=14)
|
|
216
|
+
* const result = st.maxRight(0, sum => sum < 10);
|
|
217
|
+
* console.log(result); // 3;
|
|
434
218
|
*/
|
|
435
219
|
maxRight(left: number, predicate: (segValue: E) => boolean): number {
|
|
436
220
|
if (left >= this._n) return this._n - 1;
|
|
437
|
-
|
|
438
221
|
let acc = this._identity;
|
|
439
222
|
if (!predicate(acc)) return left - 1;
|
|
440
|
-
|
|
441
223
|
let pos = this._treeSize + left;
|
|
442
|
-
|
|
443
224
|
// Go up while we're a right child or predicate still holds
|
|
444
225
|
while (true) {
|
|
445
226
|
// Find the lowest relevant node
|
|
@@ -453,19 +234,16 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
453
234
|
pos = 2 * pos; // go left (dig deeper)
|
|
454
235
|
}
|
|
455
236
|
}
|
|
456
|
-
|
|
457
237
|
// At leaf level
|
|
458
238
|
const combined = this._merger(acc, this._tree[pos]);
|
|
459
239
|
if (!predicate(combined)) {
|
|
460
240
|
return pos - this._treeSize - 1;
|
|
461
241
|
}
|
|
462
242
|
acc = combined;
|
|
463
|
-
|
|
464
243
|
// Move to next segment
|
|
465
244
|
pos++;
|
|
466
245
|
// Check if we've gone past the end
|
|
467
246
|
if (pos - this._treeSize >= this._n) return this._n - 1;
|
|
468
|
-
|
|
469
247
|
// Go up while we're a right child
|
|
470
248
|
while (pos > 1 && (pos & 1) === 0) {
|
|
471
249
|
pos >>= 1;
|
|
@@ -480,65 +258,20 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
480
258
|
* Returns right+1 if predicate(identity) is false.
|
|
481
259
|
* Returns 0 if predicate holds for the entire range [0, right].
|
|
482
260
|
* Time: O(log n)
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
* @example
|
|
526
|
-
* // Find leftmost position where predicate holds
|
|
527
|
-
* const st = SegmentTree.sum([3, 1, 4, 1, 5]);
|
|
528
|
-
* // minLeft(5, sum => sum < 7) — suffix sums from right
|
|
529
|
-
* // From right: [5]=5 < 7, [1,5]=6 < 7, [4,1,5]=10 ≥ 7
|
|
530
|
-
* const result = st.minLeft(5, sum => sum < 7);
|
|
531
|
-
* console.log(result); // 3;
|
|
261
|
+
* @example
|
|
262
|
+
* // Find leftmost position where predicate holds
|
|
263
|
+
* const st = SegmentTree.sum([3, 1, 4, 1, 5]);
|
|
264
|
+
* // minLeft(5, sum => sum < 7) — suffix sums from right
|
|
265
|
+
* // From right: [5]=5 < 7, [1,5]=6 < 7, [4,1,5]=10 ≥ 7
|
|
266
|
+
* const result = st.minLeft(5, sum => sum < 7);
|
|
267
|
+
* console.log(result); // 3;
|
|
532
268
|
*/
|
|
533
269
|
minLeft(right: number, predicate: (segValue: E) => boolean): number {
|
|
534
270
|
if (right < 0) return 0;
|
|
535
271
|
if (right >= this._n) right = this._n - 1;
|
|
536
|
-
|
|
537
272
|
let acc = this._identity;
|
|
538
273
|
if (!predicate(acc)) return right + 1;
|
|
539
|
-
|
|
540
274
|
let pos = this._treeSize + right;
|
|
541
|
-
|
|
542
275
|
while (true) {
|
|
543
276
|
while (pos < this._treeSize) {
|
|
544
277
|
const combined = this._merger(this._tree[2 * pos + 1], acc);
|
|
@@ -549,17 +282,14 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
549
282
|
pos = 2 * pos + 1; // go right (dig deeper)
|
|
550
283
|
}
|
|
551
284
|
}
|
|
552
|
-
|
|
553
285
|
const combined = this._merger(this._tree[pos], acc);
|
|
554
286
|
if (!predicate(combined)) {
|
|
555
287
|
return pos - this._treeSize + 1;
|
|
556
288
|
}
|
|
557
289
|
acc = combined;
|
|
558
|
-
|
|
559
290
|
// Move to previous segment
|
|
560
291
|
if (pos === this._treeSize) return 0;
|
|
561
292
|
pos--;
|
|
562
|
-
|
|
563
293
|
// Go up while we're a left child
|
|
564
294
|
while (pos > 1 && (pos & 1) === 1) {
|
|
565
295
|
pos >>= 1;
|
|
@@ -569,12 +299,6 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
569
299
|
}
|
|
570
300
|
}
|
|
571
301
|
|
|
572
|
-
// ─── Standard interface ────────────────────────────────────
|
|
573
|
-
|
|
574
|
-
get size(): number {
|
|
575
|
-
return this._n;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
302
|
isEmpty(): boolean {
|
|
579
303
|
return this._n === 0;
|
|
580
304
|
}
|
|
@@ -629,5 +353,3 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
629
353
|
console.log(this.toArray());
|
|
630
354
|
}
|
|
631
355
|
}
|
|
632
|
-
|
|
633
|
-
|