Topics
Useful for efficiently applying multiple range updates (e.g., add x
 to [l, r]
) followed by queries. Construction is easy:
- InitializeÂ
diff[0] = A[0]
,Âdiff[i] = A[i] - A[i-1]
 forÂi > 0
- To updateÂ
[l, r]
 byÂx
:Âdiff[l] += x
,Âdiff[r+1] -= x
- Reconstruct array via prefix sums ofÂ
diff
Say, we update [1, 2]
by x
. Our difference array: [A[0], (A[1] - A[0] + x), (A[2] - A[1]), (A[3] - A[2] - x), ...]
. When we do prefix sum, due to the telescope effect, we get: [A[0], A[1]+x, A[2]+x, A[3], ...]
which is as desired.
Time Complexity: Range update: O(1), Reconstruction: O(n), query : O(1).
Note
In many problems, where we start out with an array of all 0’s and are asked to do range updates, all we do is point updates on array of 0’s:
diff[l]+=x
anddiff[r+1]-=x
. We still call the concept “difference arrays”, even though we don’t subtract and initialize explicitly.
Tip
Common strategy is to not create the difference array, instead create an aux array of 0’s and do point updates on it and finally add the aux array with the original array point wise. Example:
arr=[1, 2, 3, 4]
, and we want to update[1, 2]
withx
. Our aux array is[0, 0, 0, 0]
and we do point updates on it →[0, x, 0, -x]
. Performing prefix sum on the aux array gives us →[0, x, x, 0]
and we can finally doarr+aux
and get →[1, 2+x, 3+x, 4]
which is desired. This makes dealing with [[2 Zettels/difference arrays#2D Range Updates|#2D Range Updates]] straightforward.
2D Range Updates
Difference Array for 1D Range Updates can be extended to 2D arrays for efficient range updates. For a 2D array, a range update is defined by the top-left corner (r1, c1)
and bottom-right corner (r2, c2)
. As mentioned previous, we create an aux array of 0’s (instead of dealing with original array directly) and update the ranges with a value val
.
aux_arr[r1][c1] += val
if (c2 + 1 < cols): aux_arr[r1][c2 + 1] -= val
if (r2 + 1 < rows): aux_arr[r2 + 1][c1] -= val
if (r2 + 1 < rows && c2 + 1 < cols): aux_arr[r2 + 1][c2 + 1] += val
Here, rows
and cols
are the dimensions of the 2D array. We can perform the point updates any number of times in constant time.
Once we are done updating, we calculate the 2D prefix sums of the aux_arr
:
for i in range(rows):
for j in range(cols):
if (i > 0): aux_arr[i][j] += aux_arr[i-1][j]
if (j > 0) aux_arr[i][j] += aux_arr[i][j-1]
if (i > 0 && j > 0) aux_arr[i][j] -= aux_arr[i-1][j-1]
After this operation, aux_arr
will hold the “cumulative updates” and we can do arr[i][j] += aux_arr[i][j]
to “apply” the effect of doing all the range updates.
Minimal Example:
Consider a 3x3 array. We want to update the region (0, 0) to (1, 1) with a value of 5.
Initial aux_arr
(3x3):
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]
Update range (0, 0) to (1, 1) with value 5:
aux_arr[0][0] += 5; // aux_arr[0][0] becomes 5
aux_arr[0][1+1] -= 5; // aux_arr[0][2] becomes -5
aux_arr[1+1][0] -= 5; // aux_arr[2][0] becomes -5
aux_arr[1+1][1+1] += 5; // aux_arr[2][2] becomes 5
Updated aux_arr
:
[[ 5, 0, -5],
[ 0, 0, 0],
[-5, 0, 5]]
Calculate 2D prefix sum to get the final array:
After prefix sum calculation aux_arr
becomes:
[[ 5, 5, 0],
[ 5, 5, 0],
[ 0, 0, 0]]
This correctly reflects that the region from (0, 0) to (1, 1) is updated to 5, and the rest remains 0.