binary-tree-typed 2.4.5 → 2.5.0

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 (76) hide show
  1. package/README.md +0 -84
  2. package/dist/cjs/index.cjs +867 -404
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs-legacy/index.cjs +864 -401
  5. package/dist/cjs-legacy/index.cjs.map +1 -1
  6. package/dist/esm/index.mjs +867 -404
  7. package/dist/esm/index.mjs.map +1 -1
  8. package/dist/esm-legacy/index.mjs +864 -401
  9. package/dist/esm-legacy/index.mjs.map +1 -1
  10. package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
  11. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +128 -51
  12. package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +210 -164
  13. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +429 -78
  14. package/dist/types/data-structures/binary-tree/bst.d.ts +311 -28
  15. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +212 -32
  16. package/dist/types/data-structures/binary-tree/segment-tree.d.ts +218 -152
  17. package/dist/types/data-structures/binary-tree/tree-map.d.ts +1281 -5
  18. package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +1087 -201
  19. package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +858 -65
  20. package/dist/types/data-structures/binary-tree/tree-set.d.ts +1133 -5
  21. package/dist/types/data-structures/graph/directed-graph.d.ts +219 -47
  22. package/dist/types/data-structures/graph/map-graph.d.ts +59 -1
  23. package/dist/types/data-structures/graph/undirected-graph.d.ts +204 -59
  24. package/dist/types/data-structures/hash/hash-map.d.ts +230 -77
  25. package/dist/types/data-structures/heap/heap.d.ts +287 -99
  26. package/dist/types/data-structures/heap/max-heap.d.ts +46 -0
  27. package/dist/types/data-structures/heap/min-heap.d.ts +59 -0
  28. package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +286 -44
  29. package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +278 -65
  30. package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +415 -12
  31. package/dist/types/data-structures/matrix/matrix.d.ts +331 -0
  32. package/dist/types/data-structures/priority-queue/max-priority-queue.d.ts +57 -0
  33. package/dist/types/data-structures/priority-queue/min-priority-queue.d.ts +60 -0
  34. package/dist/types/data-structures/priority-queue/priority-queue.d.ts +60 -0
  35. package/dist/types/data-structures/queue/deque.d.ts +272 -65
  36. package/dist/types/data-structures/queue/queue.d.ts +211 -42
  37. package/dist/types/data-structures/stack/stack.d.ts +174 -32
  38. package/dist/types/data-structures/trie/trie.d.ts +213 -43
  39. package/dist/types/types/data-structures/binary-tree/segment-tree.d.ts +1 -1
  40. package/dist/types/types/data-structures/linked-list/skip-linked-list.d.ts +1 -4
  41. package/dist/umd/binary-tree-typed.js +860 -397
  42. package/dist/umd/binary-tree-typed.js.map +1 -1
  43. package/dist/umd/binary-tree-typed.min.js +2 -2
  44. package/dist/umd/binary-tree-typed.min.js.map +1 -1
  45. package/package.json +2 -2
  46. package/src/data-structures/base/iterable-element-base.ts +4 -5
  47. package/src/data-structures/binary-tree/avl-tree.ts +134 -51
  48. package/src/data-structures/binary-tree/binary-indexed-tree.ts +302 -247
  49. package/src/data-structures/binary-tree/binary-tree.ts +429 -79
  50. package/src/data-structures/binary-tree/bst.ts +335 -34
  51. package/src/data-structures/binary-tree/red-black-tree.ts +290 -97
  52. package/src/data-structures/binary-tree/segment-tree.ts +372 -248
  53. package/src/data-structures/binary-tree/tree-map.ts +1284 -6
  54. package/src/data-structures/binary-tree/tree-multi-map.ts +1094 -211
  55. package/src/data-structures/binary-tree/tree-multi-set.ts +858 -65
  56. package/src/data-structures/binary-tree/tree-set.ts +1136 -9
  57. package/src/data-structures/graph/directed-graph.ts +219 -47
  58. package/src/data-structures/graph/map-graph.ts +59 -1
  59. package/src/data-structures/graph/undirected-graph.ts +204 -59
  60. package/src/data-structures/hash/hash-map.ts +230 -77
  61. package/src/data-structures/heap/heap.ts +287 -99
  62. package/src/data-structures/heap/max-heap.ts +46 -0
  63. package/src/data-structures/heap/min-heap.ts +59 -0
  64. package/src/data-structures/linked-list/doubly-linked-list.ts +286 -44
  65. package/src/data-structures/linked-list/singly-linked-list.ts +278 -65
  66. package/src/data-structures/linked-list/skip-linked-list.ts +689 -90
  67. package/src/data-structures/matrix/matrix.ts +416 -12
  68. package/src/data-structures/priority-queue/max-priority-queue.ts +57 -0
  69. package/src/data-structures/priority-queue/min-priority-queue.ts +60 -0
  70. package/src/data-structures/priority-queue/priority-queue.ts +60 -0
  71. package/src/data-structures/queue/deque.ts +272 -65
  72. package/src/data-structures/queue/queue.ts +211 -42
  73. package/src/data-structures/stack/stack.ts +174 -32
  74. package/src/data-structures/trie/trie.ts +213 -43
  75. package/src/types/data-structures/binary-tree/segment-tree.ts +1 -1
  76. package/src/types/data-structures/linked-list/skip-linked-list.ts +2 -1
@@ -5,328 +5,383 @@
5
5
  * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
6
6
  * @license MIT License
7
7
  */
8
- import { getMSB } from '../../utils';
9
8
  import { ERR } from '../../common';
10
9
 
11
10
  /**
11
+ * Binary Indexed Tree (Fenwick Tree).
12
12
  *
13
+ * Efficient prefix sums and point updates in O(log n).
14
+ * Standard array-based implementation per C++ competitive programming conventions.
15
+ *
16
+ * All indices are 0-based externally; internally converted to 1-based for BIT arithmetic.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const bit = new BinaryIndexedTree(6);
21
+ * bit.update(0, 3); // index 0 += 3
22
+ * bit.update(1, 2); // index 1 += 2
23
+ * bit.update(2, 7); // index 2 += 7
24
+ *
25
+ * bit.query(2); // prefix sum [0..2] = 12
26
+ * bit.queryRange(1, 2); // range sum [1..2] = 9
27
+ * bit.get(1); // point value at index 1 = 2
28
+ * ```
13
29
  */
14
- export class BinaryIndexedTree {
15
- protected readonly _freq: number;
16
- protected readonly _max: number;
30
+ export class BinaryIndexedTree implements Iterable<number> {
31
+ protected readonly _size: number;
32
+ protected _tree: number[]; // 1-indexed BIT array
17
33
 
18
34
  /**
19
- * The constructor initializes the properties of an object, including default frequency, maximum
20
- * value, a freqMap data structure, the most significant bit, and the count of negative frequencies.
21
- * @param - - `frequency`: The default frequency value. It is optional and has a default
22
- * value of 0.
35
+ * Construct a BIT of given size (all zeros), or from an initial values array.
36
+ * @param sizeOrElements - number of elements, or an array of initial values
23
37
  */
24
- constructor({ frequency = 0, max }: { frequency?: number; max: number }) {
25
- this._freq = frequency;
26
- this._max = max;
27
- this._freqMap = { 0: 0 };
28
- this._msb = getMSB(max);
29
- this._negativeCount = frequency < 0 ? max : 0;
30
- }
31
-
32
- protected _freqMap: Record<number, number>;
33
-
34
- /**
35
- * The function returns the frequency map of numbers.
36
- * @returns The `_freqMap` property, which is a record with number keys and number values, is being
37
- * returned.
38
- */
39
- get freqMap(): Record<number, number> {
40
- return this._freqMap;
41
- }
42
-
43
- protected _msb: number;
44
-
45
- /**
46
- * The function returns the value of the _msb property.
47
- * @returns The `_msb` property of the object.
48
- */
49
- get msb(): number {
50
- return this._msb;
38
+ constructor(sizeOrElements: number | number[]) {
39
+ if (Array.isArray(sizeOrElements)) {
40
+ this._size = sizeOrElements.length;
41
+ this._tree = new Array(this._size + 1).fill(0);
42
+ for (let i = 0; i < this._size; i++) {
43
+ this._pointUpdate(i + 1, sizeOrElements[i]);
44
+ }
45
+ } else {
46
+ if (!Number.isInteger(sizeOrElements) || sizeOrElements < 0) {
47
+ throw new RangeError(ERR.invalidArgument('size must be a non-negative integer', 'BinaryIndexedTree'));
48
+ }
49
+ this._size = sizeOrElements;
50
+ this._tree = new Array(this._size + 1).fill(0);
51
+ }
51
52
  }
52
53
 
53
- protected _negativeCount: number;
54
+ // ─── Core operations ──────────────────────────────────────────
54
55
 
55
56
  /**
56
- * The function returns the value of the _negativeCount property.
57
- * @returns The method is returning the value of the variable `_negativeCount`, which is of type
58
- * `number`.
57
+ * Point update: add delta to the value at index (0-based).
58
+ * Time: O(log n)
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+ * @example
74
+ * // Add delta at index
75
+ * const bit = new BinaryIndexedTree([1, 2, 3, 4, 5]);
76
+ * bit.update(2, 7);
77
+ * console.log(bit.get(2)); // 10;
59
78
  */
60
- get negativeCount(): number {
61
- return this._negativeCount;
62
- }
63
-
64
- /**
65
- * The above function returns the value of the protected variable `_freq`.
66
- * @returns The frequency value stored in the protected variable `_freq`.
67
- */
68
- get freq(): number {
69
- return this._freq;
70
- }
71
-
72
- /**
73
- * The above function returns the maximum value.
74
- * @returns The maximum value stored in the variable `_max`.
75
- */
76
- get max(): number {
77
- return this._max;
79
+ update(index: number, delta: number): void {
80
+ this._checkIndex(index);
81
+ this._pointUpdate(index + 1, delta);
78
82
  }
79
83
 
80
84
  /**
81
- * The function "readSingle" reads a single number from a specified index.
82
- * @param {number} index - The `index` parameter is a number that represents the index of an element in a
83
- * collection or array.
84
- * @returns a number.
85
+ * Point set: set the value at index to an absolute value (0-based).
86
+ * Time: O(log n)
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+ * @example
103
+ * // Set value at index
104
+ * const bit = new BinaryIndexedTree([1, 2, 3]);
105
+ * bit.set(1, 10);
106
+ * console.log(bit.get(1)); // 10;
85
107
  */
86
- readSingle(index: number): number {
108
+ set(index: number, value: number): void {
87
109
  this._checkIndex(index);
88
- return this._readSingle(index);
110
+ const current = this.get(index);
111
+ this._pointUpdate(index + 1, value - current);
89
112
  }
90
113
 
91
114
  /**
92
- * The "update" function updates the value at a given index by adding a delta and triggers a callback
93
- * to notify of the change.
94
- * @param {number} position - The `index` parameter represents the index of the element that needs to be
95
- * updated in the data structure.
96
- * @param {number} change - The "delta" parameter represents the change in value that needs to be
97
- * applied to the frequency at the specified index.
115
+ * Get the point value at index (0-based).
116
+ * Time: O(log n)
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+ * @example
132
+ * // Get value at index
133
+ * const bit = new BinaryIndexedTree([1, 2, 3]);
134
+ * console.log(bit.get(0)); // 1;
135
+ * console.log(bit.get(2)); // 3;
98
136
  */
99
- update(position: number, change: number): void {
100
- this._checkIndex(position);
101
- const freqCur = this._readSingle(position);
102
-
103
- this._update(position, change);
104
- this._updateNegativeCount(freqCur, freqCur + change);
137
+ get(index: number): number {
138
+ this._checkIndex(index);
139
+ return this._pointQuery(index + 1);
105
140
  }
106
141
 
107
142
  /**
108
- * The function "writeSingle" checks the index and writes a single value with a given frequency.
109
- * @param {number} index - The `index` parameter is a number that represents the index of an element. It
110
- * is used to identify the specific element that needs to be written.
111
- * @param {number} freq - The `freq` parameter represents the frequency value that needs to be
112
- * written.
143
+ * Prefix sum query: returns sum of elements [0..index] (inclusive, 0-based).
144
+ * Time: O(log n)
145
+
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+ * @example
161
+ * // Prefix sum
162
+ * const bit = new BinaryIndexedTree([1, 2, 3, 4]);
163
+ * console.log(bit.query(2)); // 6;
113
164
  */
114
- writeSingle(index: number, freq: number): void {
165
+ query(index: number): number {
115
166
  this._checkIndex(index);
116
- this._writeSingle(index, freq);
167
+ return this._prefixSum(index + 1);
117
168
  }
118
169
 
119
170
  /**
120
- * The read function takes a count parameter, checks if it is an integer, and returns the result of
121
- * calling the _read function with the count parameter clamped between 0 and the maximum value.
122
- * @param {number} count - The `count` parameter is a number that represents the number of items to
123
- * read.
124
- * @returns a number.
171
+ * Range sum query: returns sum of elements [start..end] (inclusive, 0-based).
172
+ * Time: O(log n)
173
+
174
+
175
+
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+
186
+
187
+ * @example
188
+ * // Range sum
189
+ * const bit = new BinaryIndexedTree([1, 2, 3, 4]);
190
+ * console.log(bit.queryRange(1, 2)); // 5;
125
191
  */
126
- read(count: number): number {
127
- if (!Number.isInteger(count)) {
128
- throw new Error(ERR.invalidArgument('count must be an integer', 'BinaryIndexedTree'));
129
- }
130
- return this._read(Math.max(Math.min(count, this.max), 0));
192
+ queryRange(start: number, end: number): number {
193
+ this._checkIndex(start);
194
+ this._checkIndex(end);
195
+ if (start > end) return 0;
196
+ if (start === 0) return this._prefixSum(end + 1);
197
+ return this._prefixSum(end + 1) - this._prefixSum(start);
131
198
  }
132
199
 
200
+ // ─── Binary search ───────────────────────────────────────────
201
+
133
202
  /**
134
- * The function returns the lower bound of a non-descending sequence that sums up to a given number.
135
- * @param {number} sum - The `sum` parameter is a number that represents the target sum that we want
136
- * to find in the sequence.
137
- * @returns The lowerBound function is returning a number.
203
+ * Find the smallest index i such that prefix sum [0..i] >= sum.
204
+ * Requires all values to be non-negative (behavior undefined otherwise).
205
+ * Returns size if no such index exists.
206
+ * Time: O(log n)
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
219
+
220
+
221
+
222
+ * @example
223
+ * // Find index with prefix sum ≥ target
224
+ * const bit = new BinaryIndexedTree([1, 2, 3, 4]);
225
+ * const idx = bit.lowerBound(4);
226
+ * console.log(idx); // >= 0;
138
227
  */
139
228
  lowerBound(sum: number): number {
140
- if (this.negativeCount > 0) {
141
- throw new Error(ERR.invalidOperation('Sequence is not non-descending.', 'BinaryIndexedTree'));
229
+ let pos = 0;
230
+ let bitMask = this._highBit(this._size);
231
+
232
+ while (bitMask > 0) {
233
+ const next = pos + bitMask;
234
+ if (next <= this._size && this._tree[next] < sum) {
235
+ sum -= this._tree[next];
236
+ pos = next;
237
+ }
238
+ bitMask >>= 1;
142
239
  }
143
- return this._binarySearch(sum, (x, y) => x < y);
144
- }
145
240
 
146
- /**
147
- * The upperBound function returns the index of the first element in a sequence that is greater than
148
- * or equal to a given sum.
149
- * @param {number} sum - The "sum" parameter is a number that represents the target sum that we want
150
- * to find in the sequence.
151
- * @returns The upperBound function is returning a number.
152
- */
153
- upperBound(sum: number): number {
154
- if (this.negativeCount > 0) {
155
- throw new Error(ERR.invalidOperation('Sequence must not be descending.', 'BinaryIndexedTree'));
156
- }
157
- return this._binarySearch(sum, (x, y) => x <= y);
241
+ return pos; // 0-based
158
242
  }
159
243
 
160
244
  /**
161
- * The function calculates the prefix sum of an array using a binary indexed tree.
162
- * @param {number} i - The parameter "i" in the function "getPrefixSum" represents the index of the element in the
163
- * array for which we want to calculate the prefix sum.
164
- * @returns The function `getPrefixSum` returns the prefix sum of the elements in the binary indexed tree up to index
165
- * `i`.
245
+ * Find the smallest index i such that prefix sum [0..i] > sum.
246
+ * Requires all values to be non-negative (behavior undefined otherwise).
247
+ * Returns size if no such index exists.
248
+ * Time: O(log n)
249
+
250
+
251
+ * @example
252
+ * // Find index with prefix sum > target
253
+ * const bit = new BinaryIndexedTree([1, 2, 3, 4]);
254
+ * const idx = bit.upperBound(4);
255
+ * console.log(idx); // >= 0;
166
256
  */
167
- getPrefixSum(i: number): number {
168
- this._checkIndex(i);
169
- i++; // Convert to 1-based index
170
-
171
- let sum = 0;
172
- while (i > 0) {
173
- sum += this._getFrequency(i);
174
- i -= i & -i;
257
+ upperBound(sum: number): number {
258
+ let pos = 0;
259
+ let bitMask = this._highBit(this._size);
260
+
261
+ while (bitMask > 0) {
262
+ const next = pos + bitMask;
263
+ if (next <= this._size && this._tree[next] <= sum) {
264
+ sum -= this._tree[next];
265
+ pos = next;
266
+ }
267
+ bitMask >>= 1;
175
268
  }
176
269
 
177
- return sum;
270
+ return pos; // 0-based
178
271
  }
179
272
 
180
- /**
181
- * The function returns the value of a specific index in a freqMap data structure, or a default value if
182
- * the index is not found.
183
- * @param {number} index - The `index` parameter is a number that represents the index of a node in a
184
- * freqMap data structure.
185
- * @returns a number.
186
- */
187
- protected _getFrequency(index: number): number {
188
- if (index in this.freqMap) {
189
- return this.freqMap[index];
190
- }
273
+ // ─── Standard interface ──────────────────────────────────────
191
274
 
192
- return this.freq * (index & -index);
275
+ get size(): number {
276
+ return this._size;
193
277
  }
194
278
 
195
- /**
196
- * The function _updateFrequency adds a delta value to the element at the specified index in the freqMap array.
197
- * @param {number} index - The index parameter is a number that represents the index of the freqMap
198
- * element that needs to be updated.
199
- * @param {number} delta - The `delta` parameter represents the change in value that needs to be
200
- * added to the freqMap at the specified `index`.
201
- */
202
- protected _updateFrequency(index: number, delta: number): void {
203
- this.freqMap[index] = this._getFrequency(index) + delta;
279
+ isEmpty(): boolean {
280
+ return this._size === 0;
204
281
  }
205
282
 
206
- /**
207
- * The function checks if the given index is valid and within the range.
208
- * @param {number} index - The parameter "index" is of type number and represents the index value
209
- * that needs to be checked.
210
- */
211
- protected _checkIndex(index: number): void {
212
- if (!Number.isInteger(index)) {
213
- throw new TypeError(ERR.invalidIndex('BinaryIndexedTree'));
214
- }
215
- if (index < 0 || index >= this.max) {
216
- throw new RangeError(ERR.indexOutOfRange(index, 0, this.max - 1, 'BinaryIndexedTree'));
217
- }
283
+ clear(): void {
284
+ this._tree.fill(0);
218
285
  }
219
286
 
220
- /**
221
- * The function calculates the sum of elements in an array up to a given index using a binary indexed
222
- * freqMap.
223
- * @param {number} index - The `index` parameter is a number that represents the index of an element in a
224
- * data structure.
225
- * @returns a number.
226
- */
227
- protected _readSingle(index: number): number {
228
- index = index + 1;
229
- let sum = this._getFrequency(index);
230
- const z = index - (index & -index);
231
-
232
- index--;
233
-
234
- while (index !== z) {
235
- sum -= this._getFrequency(index);
236
- index -= index & -index;
237
- }
238
-
239
- return sum;
287
+ clone(): BinaryIndexedTree {
288
+ return new BinaryIndexedTree(this.toArray());
240
289
  }
241
290
 
242
291
  /**
243
- * The function `_updateNegativeCount` updates a counter based on changes in frequency values.
244
- * @param {number} freqCur - The current frequency value.
245
- * @param {number} freqNew - The freqNew parameter represents the new frequency value.
292
+ * Returns the point values as a plain array.
293
+ * Time: O(n log n)
294
+
295
+
296
+ * @example
297
+ * // Convert to array
298
+ * const bit = new BinaryIndexedTree([1, 2, 3]);
299
+ * console.log(bit.toArray()); // [1, 2, 3];
246
300
  */
247
- protected _updateNegativeCount(freqCur: number, freqNew: number): void {
248
- if (freqCur < 0 && freqNew >= 0) {
249
- this._negativeCount--;
250
- } else if (freqCur >= 0 && freqNew < 0) {
251
- this._negativeCount++;
301
+ toArray(): number[] {
302
+ const result: number[] = [];
303
+ for (let i = 0; i < this._size; i++) {
304
+ result.push(this._pointQuery(i + 1));
252
305
  }
306
+ return result;
253
307
  }
254
308
 
255
309
  /**
256
- * The `_update` function updates the values in a binary indexed freqMap starting from a given index and
257
- * propagating the changes to its parent nodes.
258
- * @param {number} index - The `index` parameter is a number that represents the index of the element in
259
- * the data structure that needs to be updated.
260
- * @param {number} delta - The `delta` parameter represents the change in value that needs to be
261
- * applied to the elements in the data structure.
310
+ * Iterate over point values in index order.
262
311
  */
263
- protected _update(index: number, delta: number): void {
264
- index = index + 1;
312
+ [Symbol.iterator](): IterableIterator<number> {
313
+ const size = this._size;
314
+ let i = 0;
315
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
316
+ const self = this;
317
+ return {
318
+ [Symbol.iterator]() {
319
+ return this;
320
+ },
321
+ next(): IteratorResult<number> {
322
+ if (i < size) {
323
+ return { value: self._pointQuery(i++ + 1), done: false };
324
+ }
325
+ return { value: undefined as any, done: true };
326
+ }
327
+ };
328
+ }
265
329
 
266
- while (index <= this.max) {
267
- this._updateFrequency(index, delta);
268
- index += index & -index;
330
+ forEach(callback: (value: number, index: number) => void): void {
331
+ for (let i = 0; i < this._size; i++) {
332
+ callback(this._pointQuery(i + 1), i);
269
333
  }
270
334
  }
271
335
 
272
- /**
273
- * The `_writeSingle` function updates the frequency at a specific index and triggers a callback if
274
- * the frequency has changed.
275
- * @param {number} index - The `index` parameter is a number that represents the index of the element
276
- * being modified or accessed.
277
- * @param {number} freq - The `freq` parameter represents the new frequency value that needs to be
278
- * written to the specified index `index`.
279
- */
280
- protected _writeSingle(index: number, freq: number): void {
281
- const freqCur = this._readSingle(index);
282
-
283
- this._update(index, freq - freqCur);
284
- this._updateNegativeCount(freqCur, freq);
336
+ print(): void {
337
+ console.log(this.toArray());
285
338
  }
286
339
 
287
- /**
288
- * The `_read` function calculates the sum of values in a binary freqMap up to a given count.
289
- * @param {number} count - The `count` parameter is a number that represents the number of elements
290
- * to read from the freqMap.
291
- * @returns the sum of the values obtained from calling the `_getFrequency` method for each index in the
292
- * range from `count` to 1.
293
- */
294
- protected _read(count: number): number {
295
- let index = count;
340
+ // ─── Internal helpers ─────────────────────────────────────────
341
+
342
+ /** 1-based prefix sum up to pos (inclusive). */
343
+ protected _prefixSum(pos: number): number {
296
344
  let sum = 0;
297
- while (index) {
298
- sum += this._getFrequency(index);
299
- index -= index & -index;
345
+ while (pos > 0) {
346
+ sum += this._tree[pos];
347
+ pos -= pos & -pos;
300
348
  }
301
-
302
349
  return sum;
303
350
  }
304
351
 
305
- /**
306
- * The function `_binarySearch` performs a binary search to find the largest number that satisfies a given
307
- * condition.
308
- * @param {number} sum - The sum parameter is a number that represents the target sum value.
309
- * @param before - The `before` parameter is a function that takes two numbers `x` and `y` as
310
- * arguments and returns a boolean value. It is used to determine if `x` is less than or equal to
311
- * `y`. The purpose of this function is to compare two numbers and determine their order.
312
- * @returns the value of the variable "left".
313
- */
314
- protected _binarySearch(sum: number, before: (x: number, y: number) => boolean): number {
315
- let left = 0;
316
- let right = this.msb << 1;
317
- let sumT = sum;
352
+ /** 1-based point update: add delta to position pos. */
353
+ protected _pointUpdate(pos: number, delta: number): void {
354
+ while (pos <= this._size) {
355
+ this._tree[pos] += delta;
356
+ pos += pos & -pos;
357
+ }
358
+ }
318
359
 
319
- while (right > left + 1) {
320
- const middle = (left + right) >> 1;
321
- const sumM = this._getFrequency(middle);
360
+ /** 1-based point query: get exact value at pos. */
361
+ protected _pointQuery(pos: number): number {
362
+ let val = this._tree[pos];
363
+ const lca = pos - (pos & -pos); // parent in prefix-sum sense
364
+ pos--;
365
+ while (pos > lca) {
366
+ val -= this._tree[pos];
367
+ pos -= pos & -pos;
368
+ }
369
+ return val;
370
+ }
322
371
 
323
- if (middle <= this.max && before(sumM, sumT)) {
324
- sumT -= sumM;
325
- left = middle;
326
- } else {
327
- right = middle;
328
- }
372
+ protected _checkIndex(index: number): void {
373
+ if (!Number.isInteger(index)) {
374
+ throw new TypeError(ERR.invalidIndex('BinaryIndexedTree'));
375
+ }
376
+ if (index < 0 || index >= this._size) {
377
+ throw new RangeError(ERR.indexOutOfRange(index, 0, this._size - 1, 'BinaryIndexedTree'));
329
378
  }
330
- return left;
379
+ }
380
+
381
+ /** Returns highest power of 2 <= n. */
382
+ protected _highBit(n: number): number {
383
+ let bit = 1;
384
+ while (bit <= n) bit <<= 1;
385
+ return bit >> 1;
331
386
  }
332
387
  }