data-structure-typed 2.5.3 → 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/.husky/pre-commit +3 -0
- package/CHANGELOG.md +1 -1
- package/MIGRATION.md +48 -0
- package/README.md +20 -2
- package/README_CN.md +20 -2
- package/SPECIFICATION.md +24 -0
- package/SPECIFICATION.zh-CN.md +24 -0
- package/dist/cjs/binary-tree.cjs +1897 -19
- package/dist/cjs/graph.cjs +174 -0
- package/dist/cjs/hash.cjs +33 -0
- package/dist/cjs/heap.cjs +71 -0
- package/dist/cjs/index.cjs +2383 -3
- package/dist/cjs/linked-list.cjs +224 -2
- package/dist/cjs/matrix.cjs +24 -0
- package/dist/cjs/priority-queue.cjs +71 -0
- package/dist/cjs/queue.cjs +221 -1
- package/dist/cjs/stack.cjs +59 -0
- package/dist/cjs/trie.cjs +62 -0
- package/dist/cjs-legacy/binary-tree.cjs +1897 -19
- package/dist/cjs-legacy/graph.cjs +174 -0
- package/dist/cjs-legacy/hash.cjs +33 -0
- package/dist/cjs-legacy/heap.cjs +71 -0
- package/dist/cjs-legacy/index.cjs +2383 -3
- package/dist/cjs-legacy/linked-list.cjs +224 -2
- package/dist/cjs-legacy/matrix.cjs +24 -0
- package/dist/cjs-legacy/priority-queue.cjs +71 -0
- package/dist/cjs-legacy/queue.cjs +221 -1
- package/dist/cjs-legacy/stack.cjs +59 -0
- package/dist/cjs-legacy/trie.cjs +62 -0
- package/dist/esm/binary-tree.mjs +1897 -19
- package/dist/esm/graph.mjs +174 -0
- package/dist/esm/hash.mjs +33 -0
- package/dist/esm/heap.mjs +71 -0
- package/dist/esm/index.mjs +2383 -3
- package/dist/esm/linked-list.mjs +224 -2
- package/dist/esm/matrix.mjs +24 -0
- package/dist/esm/priority-queue.mjs +71 -0
- package/dist/esm/queue.mjs +221 -1
- package/dist/esm/stack.mjs +59 -0
- package/dist/esm/trie.mjs +62 -0
- package/dist/esm-legacy/binary-tree.mjs +1897 -19
- package/dist/esm-legacy/graph.mjs +174 -0
- package/dist/esm-legacy/hash.mjs +33 -0
- package/dist/esm-legacy/heap.mjs +71 -0
- package/dist/esm-legacy/index.mjs +2383 -3
- package/dist/esm-legacy/linked-list.mjs +224 -2
- package/dist/esm-legacy/matrix.mjs +24 -0
- package/dist/esm-legacy/priority-queue.mjs +71 -0
- package/dist/esm-legacy/queue.mjs +221 -1
- package/dist/esm-legacy/stack.mjs +59 -0
- package/dist/esm-legacy/trie.mjs +62 -0
- package/dist/types/data-structures/base/iterable-element-base.d.ts +17 -0
- package/dist/types/data-structures/base/linear-base.d.ts +6 -0
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +36 -0
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +42 -0
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +75 -0
- package/dist/types/data-structures/binary-tree/bst.d.ts +72 -0
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +57 -0
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +18 -0
- package/dist/types/data-structures/binary-tree/tree-map.d.ts +375 -0
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +389 -0
- package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +330 -0
- package/dist/types/data-structures/binary-tree/tree-set.d.ts +438 -0
- package/dist/types/data-structures/graph/directed-graph.d.ts +30 -0
- package/dist/types/data-structures/graph/undirected-graph.d.ts +27 -0
- package/dist/types/data-structures/hash/hash-map.d.ts +33 -0
- package/dist/types/data-structures/heap/heap.d.ts +42 -0
- package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +75 -2
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +45 -0
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +54 -0
- package/dist/types/data-structures/matrix/matrix.d.ts +24 -0
- package/dist/types/data-structures/queue/deque.d.ts +90 -1
- package/dist/types/data-structures/queue/queue.d.ts +36 -0
- package/dist/types/data-structures/stack/stack.d.ts +30 -0
- package/dist/types/data-structures/trie/trie.d.ts +36 -0
- package/dist/umd/data-structure-typed.js +2383 -3
- package/dist/umd/data-structure-typed.min.js +3 -3
- 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 +30 -26
- 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/jest.integration.config.js +1 -2
- package/package.json +51 -50
- package/src/common/error.ts +15 -32
- package/src/common/index.ts +0 -3
- package/src/data-structures/base/iterable-element-base.ts +32 -3
- package/src/data-structures/base/linear-base.ts +13 -36
- package/src/data-structures/binary-tree/avl-tree.ts +31 -493
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +47 -530
- package/src/data-structures/binary-tree/binary-tree.ts +326 -1236
- package/src/data-structures/binary-tree/bst.ts +158 -1010
- package/src/data-structures/binary-tree/red-black-tree.ts +451 -1233
- package/src/data-structures/binary-tree/segment-tree.ts +73 -333
- package/src/data-structures/binary-tree/tree-map.ts +462 -4749
- package/src/data-structures/binary-tree/tree-multi-map.ts +310 -4530
- package/src/data-structures/binary-tree/tree-multi-set.ts +300 -3652
- package/src/data-structures/binary-tree/tree-set.ts +437 -4443
- package/src/data-structures/graph/abstract-graph.ts +98 -167
- package/src/data-structures/graph/directed-graph.ts +137 -532
- package/src/data-structures/graph/map-graph.ts +0 -3
- package/src/data-structures/graph/undirected-graph.ts +132 -484
- package/src/data-structures/hash/hash-map.ts +154 -549
- package/src/data-structures/heap/heap.ts +200 -753
- package/src/data-structures/linked-list/doubly-linked-list.ts +153 -809
- package/src/data-structures/linked-list/singly-linked-list.ts +122 -749
- package/src/data-structures/linked-list/skip-linked-list.ts +211 -864
- package/src/data-structures/matrix/matrix.ts +179 -494
- 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 +241 -807
- package/src/data-structures/queue/queue.ts +102 -589
- package/src/data-structures/stack/stack.ts +76 -475
- package/src/data-structures/trie/trie.ts +98 -592
- 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,57 +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
|
-
* @example
|
|
121
|
-
* // Temperature monitoring with range queries
|
|
122
|
-
* // Hourly temperatures for a day (24 readings)
|
|
123
|
-
* 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];
|
|
124
|
-
* const tree = SegmentTree.sum(temps);
|
|
125
|
-
*
|
|
126
|
-
* // Average temperature during work hours (9-17)
|
|
127
|
-
* const workSum = tree.query(9, 17);
|
|
128
|
-
* console.log(workSum / 9); // toBeCloseTo;
|
|
129
|
-
*
|
|
130
|
-
* // Sum of morning temps (6-11)
|
|
131
|
-
* 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;
|
|
132
92
|
*/
|
|
133
93
|
static min(elements: number[]): SegmentTree<number> {
|
|
134
94
|
return new SegmentTree<number>(elements, {
|
|
@@ -137,6 +97,8 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
137
97
|
});
|
|
138
98
|
}
|
|
139
99
|
|
|
100
|
+
// ─── Core operations ───────────────────────────────────────
|
|
101
|
+
|
|
140
102
|
/**
|
|
141
103
|
* Create a max segment tree.
|
|
142
104
|
* @example
|
|
@@ -152,74 +114,31 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
152
114
|
});
|
|
153
115
|
}
|
|
154
116
|
|
|
155
|
-
// ─── Core operations ───────────────────────────────────────
|
|
156
|
-
|
|
157
117
|
/**
|
|
158
118
|
* Point update: set element at index to value.
|
|
159
119
|
* Time: O(log n)
|
|
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
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
* @example
|
|
200
|
-
* // Dynamic range sum with updates
|
|
201
|
-
* // Monthly revenue data (in thousands)
|
|
202
|
-
* const revenue = [120, 95, 140, 110, 85, 130, 150, 100, 160, 125, 90, 175];
|
|
203
|
-
* const tree = SegmentTree.sum(revenue);
|
|
204
|
-
*
|
|
205
|
-
* // Q1 revenue (Jan-Mar)
|
|
206
|
-
* console.log(tree.query(0, 2)); // 355;
|
|
207
|
-
*
|
|
208
|
-
* // Update March revenue from 140 to 200
|
|
209
|
-
* tree.update(2, 200);
|
|
210
|
-
*
|
|
211
|
-
* // Q1 revenue after update
|
|
212
|
-
* console.log(tree.query(0, 2)); // 415;
|
|
213
|
-
*
|
|
214
|
-
* // H1 revenue (Jan-Jun)
|
|
215
|
-
* 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;
|
|
216
137
|
*/
|
|
217
138
|
update(index: number, value: E): void {
|
|
218
139
|
if (index < 0 || index >= this._n) return;
|
|
219
|
-
|
|
220
140
|
let pos = this._treeSize + index;
|
|
221
141
|
this._tree[pos] = value;
|
|
222
|
-
|
|
223
142
|
// Propagate up
|
|
224
143
|
pos >>= 1;
|
|
225
144
|
while (pos >= 1) {
|
|
@@ -231,68 +150,27 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
231
150
|
/**
|
|
232
151
|
* Range query: returns merger result over [start, end] (inclusive).
|
|
233
152
|
* Time: O(log n)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
* @example
|
|
274
|
-
* // Range sum query on an array
|
|
275
|
-
* const tree = SegmentTree.sum([1, 3, 5, 7, 9, 11]);
|
|
276
|
-
*
|
|
277
|
-
* // Query sum of range [1, 3] → 3 + 5 + 7 = 15
|
|
278
|
-
* console.log(tree.query(1, 3)); // 15;
|
|
279
|
-
*
|
|
280
|
-
* // Query entire range
|
|
281
|
-
* console.log(tree.query(0, 5)); // 36;
|
|
282
|
-
*
|
|
283
|
-
* // Query single element
|
|
284
|
-
* 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;
|
|
285
165
|
*/
|
|
286
166
|
query(start: number, end: number): E {
|
|
287
167
|
if (start < 0) start = 0;
|
|
288
168
|
if (end >= this._n) end = this._n - 1;
|
|
289
169
|
if (start > end) return this._identity;
|
|
290
|
-
|
|
291
170
|
let resultLeft = this._identity;
|
|
292
171
|
let resultRight = this._identity;
|
|
293
172
|
let left = this._treeSize + start;
|
|
294
173
|
let right = this._treeSize + end + 1; // exclusive
|
|
295
|
-
|
|
296
174
|
while (left < right) {
|
|
297
175
|
if (left & 1) {
|
|
298
176
|
resultLeft = this._merger(resultLeft, this._tree[left]);
|
|
@@ -305,126 +183,44 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
305
183
|
left >>= 1;
|
|
306
184
|
right >>= 1;
|
|
307
185
|
}
|
|
308
|
-
|
|
309
186
|
return this._merger(resultLeft, resultRight);
|
|
310
187
|
}
|
|
311
188
|
|
|
189
|
+
// ─── Binary search on tree (ACL-style) ─────────────────────
|
|
190
|
+
|
|
312
191
|
/**
|
|
313
192
|
* Get element at index.
|
|
314
193
|
* Time: O(1)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
-
* @example
|
|
355
|
-
* // Point access on segment tree
|
|
356
|
-
* const st = SegmentTree.sum([10, 20, 30, 40]);
|
|
357
|
-
* console.log(st.get(0)); // 10;
|
|
358
|
-
* 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;
|
|
359
199
|
*/
|
|
360
200
|
get(index: number): E {
|
|
361
201
|
if (index < 0 || index >= this._n) return this._identity;
|
|
362
202
|
return this._tree[this._treeSize + index];
|
|
363
203
|
}
|
|
364
204
|
|
|
365
|
-
// ─── Binary search on tree (ACL-style) ─────────────────────
|
|
366
|
-
|
|
367
205
|
/**
|
|
368
206
|
* Find the largest r such that predicate(query(left, r)) is true.
|
|
369
207
|
* Returns left-1 if predicate(identity) is false.
|
|
370
208
|
* Returns n-1 if predicate holds for the entire range [left, n-1].
|
|
371
209
|
* Time: O(log n)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
-
* @example
|
|
412
|
-
* // Find rightmost position where predicate holds
|
|
413
|
-
* // Prefix sums: find the rightmost index where prefix sum < 10
|
|
414
|
-
* const st = SegmentTree.sum([3, 1, 4, 1, 5]);
|
|
415
|
-
* // maxRight(0, sum => sum < 10) — prefix [3,4,8,9,14]
|
|
416
|
-
* // sum < 10 holds through index 3 (prefix=9), fails at 4 (prefix=14)
|
|
417
|
-
* const result = st.maxRight(0, sum => sum < 10);
|
|
418
|
-
* 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;
|
|
419
218
|
*/
|
|
420
219
|
maxRight(left: number, predicate: (segValue: E) => boolean): number {
|
|
421
220
|
if (left >= this._n) return this._n - 1;
|
|
422
|
-
|
|
423
221
|
let acc = this._identity;
|
|
424
222
|
if (!predicate(acc)) return left - 1;
|
|
425
|
-
|
|
426
223
|
let pos = this._treeSize + left;
|
|
427
|
-
|
|
428
224
|
// Go up while we're a right child or predicate still holds
|
|
429
225
|
while (true) {
|
|
430
226
|
// Find the lowest relevant node
|
|
@@ -438,19 +234,16 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
438
234
|
pos = 2 * pos; // go left (dig deeper)
|
|
439
235
|
}
|
|
440
236
|
}
|
|
441
|
-
|
|
442
237
|
// At leaf level
|
|
443
238
|
const combined = this._merger(acc, this._tree[pos]);
|
|
444
239
|
if (!predicate(combined)) {
|
|
445
240
|
return pos - this._treeSize - 1;
|
|
446
241
|
}
|
|
447
242
|
acc = combined;
|
|
448
|
-
|
|
449
243
|
// Move to next segment
|
|
450
244
|
pos++;
|
|
451
245
|
// Check if we've gone past the end
|
|
452
246
|
if (pos - this._treeSize >= this._n) return this._n - 1;
|
|
453
|
-
|
|
454
247
|
// Go up while we're a right child
|
|
455
248
|
while (pos > 1 && (pos & 1) === 0) {
|
|
456
249
|
pos >>= 1;
|
|
@@ -465,62 +258,20 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
465
258
|
* Returns right+1 if predicate(identity) is false.
|
|
466
259
|
* Returns 0 if predicate holds for the entire range [0, right].
|
|
467
260
|
* Time: O(log n)
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
-
* @example
|
|
508
|
-
* // Find leftmost position where predicate holds
|
|
509
|
-
* const st = SegmentTree.sum([3, 1, 4, 1, 5]);
|
|
510
|
-
* // minLeft(5, sum => sum < 7) — suffix sums from right
|
|
511
|
-
* // From right: [5]=5 < 7, [1,5]=6 < 7, [4,1,5]=10 ≥ 7
|
|
512
|
-
* const result = st.minLeft(5, sum => sum < 7);
|
|
513
|
-
* 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;
|
|
514
268
|
*/
|
|
515
269
|
minLeft(right: number, predicate: (segValue: E) => boolean): number {
|
|
516
270
|
if (right < 0) return 0;
|
|
517
271
|
if (right >= this._n) right = this._n - 1;
|
|
518
|
-
|
|
519
272
|
let acc = this._identity;
|
|
520
273
|
if (!predicate(acc)) return right + 1;
|
|
521
|
-
|
|
522
274
|
let pos = this._treeSize + right;
|
|
523
|
-
|
|
524
275
|
while (true) {
|
|
525
276
|
while (pos < this._treeSize) {
|
|
526
277
|
const combined = this._merger(this._tree[2 * pos + 1], acc);
|
|
@@ -531,17 +282,14 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
531
282
|
pos = 2 * pos + 1; // go right (dig deeper)
|
|
532
283
|
}
|
|
533
284
|
}
|
|
534
|
-
|
|
535
285
|
const combined = this._merger(this._tree[pos], acc);
|
|
536
286
|
if (!predicate(combined)) {
|
|
537
287
|
return pos - this._treeSize + 1;
|
|
538
288
|
}
|
|
539
289
|
acc = combined;
|
|
540
|
-
|
|
541
290
|
// Move to previous segment
|
|
542
291
|
if (pos === this._treeSize) return 0;
|
|
543
292
|
pos--;
|
|
544
|
-
|
|
545
293
|
// Go up while we're a left child
|
|
546
294
|
while (pos > 1 && (pos & 1) === 1) {
|
|
547
295
|
pos >>= 1;
|
|
@@ -551,12 +299,6 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
551
299
|
}
|
|
552
300
|
}
|
|
553
301
|
|
|
554
|
-
// ─── Standard interface ────────────────────────────────────
|
|
555
|
-
|
|
556
|
-
get size(): number {
|
|
557
|
-
return this._n;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
302
|
isEmpty(): boolean {
|
|
561
303
|
return this._n === 0;
|
|
562
304
|
}
|
|
@@ -611,5 +353,3 @@ export class SegmentTree<E = number> implements Iterable<E> {
|
|
|
611
353
|
console.log(this.toArray());
|
|
612
354
|
}
|
|
613
355
|
}
|
|
614
|
-
|
|
615
|
-
|