![]() |
VOOZH | about |
Given an array arr[0..N-1]. The following operations need to be performed.
Initially, all the elements in the array are 0. Queries can be in any order, i.e., there can be many updates before range sum.
Example:
Input: N = 5 // {0, 0, 0, 0, 0}
Queries: update: l = 0, r = 4, val = 2
update : l = 3, r = 4, val = 3
getRangeSum : l = 2, r = 4Output: Sum of elements of range [2, 4] is 12
Explanation: Array after first update becomes {2, 2, 2, 2, 2}
Array after second update becomes {2, 2, 2, 5, 5}
To solve the problem follow the below idea:
In the previous post, we discussed range update and point query solutions using BIT.
rangeUpdate(l, r, val) : We add 'val' to the element at index 'l'. We subtract 'val' from the element at index 'r+1'.
getElement(index) [or getSum()]: We return sum of elements from 0 to index which can be quickly obtained using BIT.
We can compute rangeSum() using getSum() queries.
rangeSum(l, r) = getSum(r) - getSum(l-1)A Simple Solution is to use the solutions discussed in the previous post. The range update query is the same. Range sum query can be achieved by doing a get query for all elements in the range.
To solve the problem follow the below idea:
We get range sum using prefix sums. How to make sure that the update is done in a way so that prefix sum can be done quickly? Consider a situation where prefix sum [0, k] (where 0 <= k < n) is needed after range update on the range [l, r]. Three cases arise as k can possibly lie in 3 regions.
- Case 1: 0 < k < l
- The update query won’t affect sum query.
- Case 2: l <= k <= r
- Consider an example: Add 2 to range [2, 4], the resultant array would be: 0 0 2 2 2
If k = 3 The sum from [0, k] = 4How to get this result?
Simply add the val from lth index to kth index. Sum is incremented by "val*(k) - val*(l-1)" after the update query.
- Case 3: k > r
- For this case, we need to add "val" from lth index to rth index. Sum is incremented by "val*r – val*(l-1)" due to an update query.
Case 1: is simple as the sum would remain the same as it was before the update.
Case 2: Sum was incremented by val*k - val*(l-1). We can find "val", it is similar to finding the ith element in range update and point query article. So we maintain one BIT for Range Update and Point Queries, this BIT will be helpful in finding the value at kth index. Now val * k is computed, how to handle extra term val*(l-1)?
In order to handle this extra term, we maintain another BIT (BIT2). Update val * (l-1) at lth index, so when the getSum query is performed on BIT2 will give the result as val*(l-1).
Case 3: The sum in case 3 was incremented by "val*r - val *(l-1)", the value of this term can be obtained using BIT2. Instead of adding, we subtract "val*(l-1) - val*r" as we can get this value from BIT2 by adding val*(l-1) as we did in case 2 and subtracting val*r in every update operation.
Update Query
Update(BITree1, l, val)
Update(BITree1, r+1, -val)
UpdateBIT2(BITree2, l, val*(l-1))
UpdateBIT2(BITree2, r+1, -val*r)Range Sum
getSum(BITTree1, k) *k) - getSum(BITTree2, k)
Follow the below steps to solve the problem:
Below is the Implementation of the above approach:
Sum of elements from [1,4] is 50
Time Complexity: O(q * log(N)) where q is the number of queries.
Auxiliary Space: O(N)