In this tutorial, I’m going to describe a problem and a simple solution to solve this to learn two dimensional cumulative sums.
You have a 2D matrix mat having n rows and m columns. You have some assigned numbers in every cell.
Row 1 | 3 | 5 | 1 | 16 | 8 | 13 |
Row 2 | 12 | 2 | 13 | 9 | 11 | 6 |
Row 3 | 7 | 10 | 6 | 12 | 4 | 7 |
Row 4 | 11 | 6 | 17 | 4 | 7 | 18 |
Row 5 | 8 | 14 | 7 | 8 | 12 | 3 |
mat | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | Col 6 |
You need to do some queries, in every queries you need to print the sum of the submatrix. You will be given the position of upper left cell and lower right cell of the matrix. Example, we need to find the sum of sub-matrix having cells (2, 3) and (4, 5).
Row 1 | 3 | 5 | 1 | 16 | 8 | 13 |
Row 2 | 12 | 2 | 13 | 9 | 11 | 6 |
Row 3 | 7 | 10 | 6 | 12 | 4 | 7 |
Row 4 | 11 | 6 | 17 | 4 | 7 | 18 |
Row 5 | 8 | 14 | 7 | 8 | 12 | 3 |
mat | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | Col 6 |
Let’s solve this problem naively first. We can run a simple nested loop to find the sum. Like this:
int sum(int x1, int y1, int x2, int y2) { |
But the complexity of this code is O(n2). This code will easily fail for higher constraints.
Let’s solve this problem efficiently.
Let’s store the cumulative sum of the matrix. We will store the cumulative sum in such a way that the cell(i, j) will have cumulative sum of the submatrix having upper left cell(1, 1) and lower right cell(i, j). How will we do that?
Let’s have another 2D matrix csum for storing the cumulative sum of the matrix mat.
Then csum[1][1] will be equal to mat[1][1] as cell(1,1) is the only cell of the submatrix having upper left cell(1, 1) and lower right cell(1, 1).
So, csum[1][1] = mat[1][1] = 3.
csum[1][2] will have the value equal to mat[1][2] + csum[1][1] as the cumulative sum upto cell(1, 2) will have the sum of every cells of the submatrix having upper left cell(1, 1) and lower right cell(1, 2). So that, by adding csum[1][1] with mat[1][2], we will get csum[1][2] which is the cumulative sum of cell(1, 1) and cell(1, 2).
So, csum[1][2] = csum[1][1] + mat[1][2] = 3 + 5 = 8.
Similarly csum[1][3] = csum[1][2] + mat[1][3] = 8 + 1 = 9 and so on. By doing the same for the other cells of row 1, we will get the cumulative sum of raw 1.
Row 1 | 3 | 8 | 9 | 25 | 33 | 46 |
Row 2 | ||||||
Row 3 | ||||||
Row 4 | ||||||
Row 5 | ||||||
csum | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | Col 6 |
Now for the cell(2, 1). The csum[2][1] will be the sum of csum[1][1] and mat[2][1].
So, csum[2][1] = csum[1][1] + mat[2][1] = 3 + 12 = 15.
Here comes a bit complex calculation. For the cell(2, 2), csum[2][2] should contain the sum of those cells of mat matrix: (1, 1), (1, 2) (2, 1) and (2, 2).
So finally, csum[2][2] = mat[2][2] + csum[1][2] + csum[2][1] - csum[1][1] = 2 + 8 + 15 - 3 = 22
We caught the pattern! We will store the cumulative sum for mat matrix as following:
csum[i][j] = mat[i][j] + csum[i - 1][j] + csum[i][j - 1] - csum[i - 1][j - 1]
The code for calculating cumulative sum is following:
void calc(int n, int m) { |
The final cumulative array will look like as following:
Row 1 | 3 | 8 | 9 | 25 | 33 | 46 |
Row 2 | 15 | 22 | 36 | 61 | 80 | 99 |
Row 3 | 22 | 39 | 59 | 96 | 119 | 145 |
Row 4 | 33 | 56 | 93 | 134 | 164 | 208 |
Row 5 | 41 | 78 | 122 | 171 | 213 | 260 |
csum | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | Col 6 |
Let’s now get back to the query part. Following is the mat matrix and we need the sum of the highlighted submatrix:
Row 1 | 3 | 5 | 1 | 16 | 8 | 13 |
Row 2 | 12 | 2 | 13 | 9 | 11 | 6 |
Row 3 | 7 | 10 | 6 | 12 | 4 | 7 |
Row 4 | 11 | 6 | 17 | 4 | 7 | 18 |
Row 5 | 8 | 14 | 7 | 8 | 12 | 3 |
mat | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | Col 6 |
The upper left of the submatrix is (2, 3) and the lower right cell is (4, 5). We can get the sum of that submatrix by doing the following:
Row 1 | 3 | 5 | 1 | 16 | 8 | 13 |
Row 2 | 12 | 2 | 13 | 9 | 11 | 6 |
Row 3 | 7 | 10 | 6 | 12 | 4 | 7 |
Row 4 | 11 | 6 | 17 | 4 | 7 | 18 |
Row 5 | 8 | 14 | 7 | 8 | 12 | 3 |
mat | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | Col 6 |
We got it! The sum of submatrix [(2, 3), (4, 5)] = csum[4][5] - csum[4][2] - csum[1][5] + csum[1][2] = 164 - 56 - 33 + 8 = 83
So if (x1, y1) is upper left cell and (x2, y2) is the lower right cell of the submatrix, the sum of that submatrix is equal to csum[x2][y2] - csum[x2][y1 - 1] - csum[x1 - 1][y2] + csum[x1 - 1][y1 - 1].
Here is the final code:
#include <bits/stdc++.h> |
You can try to solve this problem for practice.