2
* @param {number[]} nums3
* @param {number} lower4
* @param {number} upper7
var countRangeSum = function (nums, lower, upper) {8
if (nums.length === 1) return 1;9
let prefixSums = new Array(nums.length + 1);11
for (let index = 0; index < nums.length; index++) {13
prefixSums[index + 1] = nums[index];15
prefixSums[index + 1] = prefixSums[index] + nums[index];19
let sortedPrefixSums = prefixSums.slice();20
sortedPrefixSums.sort((a, b) => a - b);22
let ranks = new Map();23
for (let index = 0; index < sortedPrefixSums.length; index++) {24
ranks.set(sortedPrefixSums[index], index);28
let tree = new SegTree(sortedPrefixSums);29
const reversed = new TreeMap([...ranks.keys()]);31
function getRanks(val) {32
let lowerBound = reversed.floorKey(val + lower - 1);34
if (lowerBound !== undefined) {35
minRank = ranks.get(lowerBound) + 1;38
let upperBound = reversed.floorKey(val + upper, 0, reversed.length - 1);40
if (upperBound !== undefined) {41
maxRank = ranks.get(upperBound);43
return [minRank, maxRank];46
for (let index = prefixSums.length - 1; index >= 0; index--) {47
const [minRank, maxRank] = getRanks(prefixSums[index]);48
const c = tree.query(minRank, maxRank);51
const r = ranks.get(prefixSums[index]);63
this.lastLevelNodeAmount = 2 ** Math.ceil(Math.log2(n));64
this.offset = this.lastLevelNodeAmount - 1;67
const newIdx = this.offset + idx;68
this.arr[newIdx] = (this.arr[newIdx] ?? 0) + 1;69
this._update(newIdx, 1);72
const parentIdx = Math.ceil(idx / 2) - 1;73
if (!this.arr[parentIdx]) this.arr[parentIdx] = 0;75
this.arr[parentIdx] += diff;77
if (parentIdx > 0) this._update(parentIdx, diff);81
return this._query(i, j, 0, this.lastLevelNodeAmount, 0);83
_query(i, j, l, r, idx) {84
if (i > r || j < l) return 0;85
if (i <= l && j >= Math.min(this.size, r) - 1) {86
return this.arr[idx] ?? 0;89
const mid = l + Math.floor((r - l) / 2);90
const firstChildIdx = 2 * idx + 1;91
const secondChildIdx = 2 * idx + 2;95
return this._query(i, j, mid, r, secondChildIdx);98
return this._query(i, j, l, mid, firstChildIdx);101
const leftQuery = this._query(i, j, l, mid, firstChildIdx);102
const rightQuery = this._query(i, j, mid, r, secondChildIdx);104
return leftQuery + rightQuery;114
return this.#binarySearch(key, 0, this.arr.length - 1);117
#binarySearch(target, l, r) {119
return r < 0 ? undefined : this.arr[this.arr.length - 1];121
const mid = l + Math.floor((r - l) / 2);122
if (this.arr[mid] === target) return this.arr[mid];123
else if (this.arr[mid - 1] < target && this.arr[mid] > target)124
return this.arr[mid - 1];125
else if (this.arr[mid] > target)126
return this.#binarySearch(target, l, mid - 1);127
else return this.#binarySearch(target, mid + 1, r);