Open In App

Sum and Update Queries on 2D Matrix

Last Updated : 31 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a 2D matrix mat[][] of size NXN with all its elements initialized to 0, the task is to answer Q queries. Each query[i] can be one of the following types:

  • Type 1 [1, x, y, ele]: Update the value of cell(x, y) to val.
  • Type 2 [2, x1, y1 ,x2, y2]: Print the sum of the submatrix (x1, y1) to (x2, y2)

Print the answer of all the queries of type 2. The matrix and queries follow 0-based indexing.

Examples:

Input: N = 3, queries[][] = {{1, 2, 0, 2} , {2, 0, 0, 2, 2}, {1, 0, 0, 1}, {2, 0, 0, 2, 0} }
Output: [2, 3]
Explanation:

fenwick_1

The first query is to update the value of cell (2, 0) to 2. The second query is to take the sum of the submatrix (0, 0) to (2, 2) which is equal to 2. The third query is to update the value of cell (0, 0) to 1. The fourth query is to take the sum of the submatrix (0, 0) to submatrix (2, 0) which is equal to 3.

Input: N = 3, queries = { { 1, 0, 2, 2 }, { 1, 0, 0, 1 }, { 2, 0, 0, 2, 2 }, { 1, 0, 1, 1 }, { 2, 0, 0, 0, 2 } }
Output: [3, 4]
Explanation: The first query is to update the value of cell (0, 2) to 2. The second query is to update the value of cell (0, 0) to 1. The third query is to take the sum of the submatrix (0, 0) to (2, 2), which is equal to 3. The fourth query is to update the value of cell (0, 1) to 1 and the fifth query is to take the sum of the submatrix (0, 0) to submatrix (0, 2) which is equal to 4.

Approach: The problem can be solved using the following approach:

Since we need to answer the update and sum queries in log(N) time, we can solve them using Fenwick tree on 2D matrix. We can maintain a 2D Binary Indexed Tree to store the partial sums of the matrices.

Point Update: Whenever we have to update a cell (x, y), we start with the current row x and update all the cells in row x which stores the partial sum of cell (x, y) by changing y to y + (y & -y). Then, we move to the next row which stores the partial sum of cell (x, y) by changing x to x + (x & -x).

Range Sum: Whenever we have to find the range sum of submatrix (x1, y1) to (x2, y2) then we can calculate it using the formula: prefixSum(x2, y2) – prefixSum(x2, y1) – prefixSum(x1, y2) + prefixSum(x2, y2)

Steps to solve the problem:

  • Initialize a 2-D Binary Indexed Tree of size (N+1) * (N + 1), because of 1-based indexing.
  • To handle the updates, maintain a function update(x, y, ele) which updates all the submatrices which store the partial sum of cell (x, y)
  • To handle the queries, maintain a method getSum(x, y) which calculate the prefix sum of of submatrix (x, y) and use the formula prefixSum(x2, y2) – prefixSum(x2, y1) – prefixSum(x1, y2) + prefixSum(x2, y2) to calculate the sum of submatrices and print the answer.

Below is the implementation of the above approach:

C++14




#include <bits/stdc++.h>
#define ll long long int
using namespace std;
 
// Update query for Columns
void update_y(ll x, ll y, ll ele, vector<vector<ll> >& bit,
              ll n)
{
    while (y <= n) {
        bit[x][y] += ele;
        y += (y & -y);
    }
}
 
// Method to add ele to mat[x][y]
void update(ll x, ll y, ll ele, vector<vector<ll> >& bit,
            ll n)
{
    while (x <= n) {
        update_y(x, y, ele, bit, n);
        x += (x & -x);
    }
}
 
// Method to calculate prefix sum of columns
ll getSum_y(ll x, ll y, vector<vector<ll> >& bit)
{
    ll sum = 0;
    while (y) {
        sum += bit[x][y];
        y -= (y & -y);
    }
    return sum;
}
 
// Method to calculate prefix sum of mat[x][y]
ll getSum(ll x, ll y, vector<vector<ll> >& bit)
{
    ll sum = 0;
    while (x) {
        sum += getSum_y(x, y, bit);
        x -= (x & -x);
    }
    return sum;
}
 
int main()
{
    // Number of rows and columns
    ll n = 3;
    vector<vector<ll> > mat(n + 1, vector<ll>(n + 1, 0));
    // vector to store 2D Fenwick tree
    vector<vector<ll> > bit(n + 1, vector<ll>(n + 1, 0));
    vector<vector<ll> > queries = { { 1, 2, 0, 2 },
                                    { 2, 0, 0, 2, 2 },
                                    { 1, 0, 0, 1 },
                                    { 2, 0, 0, 2, 0 } };
    for (auto query : queries) {
        // Point Update Query
        if (query[0] == 1) {
            ll x = query[1] + 1;
            ll y = query[2] + 1;
            ll ele = query[3];
            update(x, y, ele - mat[x][y], bit, n);
            mat[x][y] = ele;
        }
        // Range Sum Query
        else {
            ll x1 = query[1] + 1;
            ll y1 = query[2] + 1;
            ll x2 = query[3] + 1;
            ll y2 = query[4] + 1;
            ll bottomRight = getSum(x2, y2, bit);
            ll topRight = getSum(x1 - 1, y2, bit);
            ll bottomLeft = getSum(x2, y1 - 1, bit);
            ll topLeft = getSum(x1 - 1, y1 - 1, bit);
            cout << bottomRight - topRight - bottomLeft
                        + topLeft
                 << " ";
        }
    }
}


Java




import java.util.ArrayList;
import java.util.List;
 
public class FenwickTree2D {
 
    // Update query for Columns
    static void update_y(int x, int y, int ele, List<List<Integer>> bit, int n) {
        while (y <= n) {
            bit.get(x).set(y, bit.get(x).get(y) + ele);
            y += (y & -y); // Update next column
        }
    }
 
    // Method to add ele to mat[x][y]
    static void update(int x, int y, int ele, List<List<Integer>> bit, int n) {
        while (x <= n) {
            update_y(x, y, ele, bit, n);
            x += (x & -x); // Update next row
        }
    }
 
    // Method to calculate prefix sum of columns
    static int getSum_y(int x, int y, List<List<Integer>> bit) {
        int sum = 0;
        while (y > 0) {
            sum += bit.get(x).get(y);
            y -= (y & -y); // Move to the parent column
        }
        return sum;
    }
 
    // Method to calculate prefix sum of mat[x][y]
    static int getSum(int x, int y, List<List<Integer>> bit) {
        int sum = 0;
        while (x > 0) {
            sum += getSum_y(x, y, bit);
            x -= (x & -x); // Move to the parent row
        }
        return sum;
    }
 
    public static void main(String[] args) {
        int n = 3;
        List<List<Integer>> mat = new ArrayList<>(n + 1);
        List<List<Integer>> bit = new ArrayList<>(n + 1);
 
        // Initialize matrices with zeros
        for (int i = 0; i <= n; i++) {
            mat.add(new ArrayList<>(List.of(0, 0, 0, 0)));
            bit.add(new ArrayList<>(List.of(0, 0, 0, 0)));
        }
 
        // List of queries
        List<List<Integer>> queries = List.of(
                List.of(1, 2, 0, 2),
                List.of(2, 0, 0, 2, 2),
                List.of(1, 0, 0, 1),
                List.of(2, 0, 0, 2, 0)
        );
 
        // Process each query
        for (List<Integer> query : queries) {
            if (query.get(0) == 1) {
                // Point Update Query
                int x = query.get(1) + 1;
                int y = query.get(2) + 1;
                int ele = query.get(3);
                update(x, y, ele - mat.get(x).get(y), bit, n);
                mat.get(x).set(y, ele);
            } else {
                // Range Sum Query
                int x1 = query.get(1) + 1;
                int y1 = query.get(2) + 1;
                int x2 = query.get(3) + 1;
                int y2 = query.get(4) + 1;
                int bottomRight = getSum(x2, y2, bit);
                int topRight = getSum(x1 - 1, y2, bit);
                int bottomLeft = getSum(x2, y1 - 1, bit);
                int topLeft = getSum(x1 - 1, y1 - 1, bit);
                System.out.print(bottomRight - topRight - bottomLeft + topLeft + " ");
            }
        }
    }
}
 
// This code is contributed by shivamgupta0987654321


Python3




def update_y(x, y, ele, bit, n):
    while y <= n:
        bit[x][y] += ele
        y += (y & -y)
 
def update(x, y, ele, bit, n):
    while x <= n:
        update_y(x, y, ele, bit, n)
        x += (x & -x)
 
def getSum_y(x, y, bit):
    sum_val = 0
    while y:
        sum_val += bit[x][y]
        y -= (y & -y)
    return sum_val
 
def getSum(x, y, bit):
    sum_val = 0
    while x:
        sum_val += getSum_y(x, y, bit)
        x -= (x & -x)
    return sum_val
 
if __name__ == "__main__":
    n = 3
    mat = [[0] * (n + 1) for _ in range(n + 1)]
    bit = [[0] * (n + 1) for _ in range(n + 1)]
 
    queries = [
        [1, 2, 0, 2],
        [2, 0, 0, 2, 2],
        [1, 0, 0, 1],
        [2, 0, 0, 2, 0]
    ]
 
    for query in queries:
        if query[0] == 1:
            x, y, ele = query[1] + 1, query[2] + 1, query[3]
            update(x, y, ele - mat[x][y], bit, n)
            mat[x][y] = ele
        else:
            x1, y1, x2, y2 = query[1] + 1, query[2] + 1, query[3] + 1, query[4] + 1
            bottom_right = getSum(x2, y2, bit)
            top_right = getSum(x1 - 1, y2, bit)
            bottom_left = getSum(x2, y1 - 1, bit)
            top_left = getSum(x1 - 1, y1 - 1, bit)
            result = bottom_right - top_right - bottom_left + top_left
            print(result, end=" ")


C#




using System;
using System.Collections.Generic;
 
class Program
{
    // Update query for Columns
    static void UpdateY(int x, int y, int ele, List<List<int>> bit, int n)
    {
        while (y <= n)
        {
            bit[x][y] += ele;
            y += (y & -y);
        }
    }
 
    // Method to add ele to mat[x][y]
    static void Update(int x, int y, int ele, List<List<int>> bit, int n)
    {
        while (x <= n)
        {
            UpdateY(x, y, ele, bit, n);
            x += (x & -x);
        }
    }
 
    // Method to calculate prefix sum of columns
    static int GetSumY(int x, int y, List<List<int>> bit)
    {
        int sum = 0;
        while (y > 0)
        {
            sum += bit[x][y];
            y -= (y & -y);
        }
        return sum;
    }
 
    // Method to calculate prefix sum of mat[x][y]
    static int GetSum(int x, int y, List<List<int>> bit)
    {
        int sum = 0;
        while (x > 0)
        {
            sum += GetSumY(x, y, bit);
            x -= (x & -x);
        }
        return sum;
    }
 
    static void Main()
    {
        // Number of rows and columns
        int n = 3;
        List<List<int>> mat = new List<List<int>>();
        List<List<int>> bit = new List<List<int>>();
        for (int i = 0; i <= n; i++)
        {
            mat.Add(new List<int>(new int[n + 1]));
            bit.Add(new List<int>(new int[n + 1]));
        }
 
        List<List<int>> queries = new List<List<int>> {
            new List<int> { 1, 2, 0, 2 },
            new List<int> { 2, 0, 0, 2, 2 },
            new List<int> { 1, 0, 0, 1 },
            new List<int> { 2, 0, 0, 2, 0 }
        };
 
        foreach (var query in queries)
        {
            // Point Update Query
            if (query[0] == 1)
            {
                int x = query[1] + 1;
                int y = query[2] + 1;
                int ele = query[3];
                Update(x, y, ele - mat[x][y], bit, n);
                mat[x][y] = ele;
            }
            // Range Sum Query
            else
            {
                int x1 = query[1] + 1;
                int y1 = query[2] + 1;
                int x2 = query[3] + 1;
                int y2 = query[4] + 1;
                int bottomRight = GetSum(x2, y2, bit);
                int topRight = GetSum(x1 - 1, y2, bit);
                int bottomLeft = GetSum(x2, y1 - 1, bit);
                int topLeft = GetSum(x1 - 1, y1 - 1, bit);
                Console.Write(bottomRight - topRight - bottomLeft + topLeft + " ");
            }
        }
    }
}


Javascript




// Update query for Columns
function update_y(x, y, ele, bit, n) {
    while (y <= n) {
        bit[x][y] += ele;
        y += (y & -y);
    }
}
 
// Method to add ele to mat[x][y]
function update(x, y, ele, bit, n) {
    while (x <= n) {
        update_y(x, y, ele, bit, n);
        x += (x & -x);
    }
}
 
// Method to calculate prefix sum of columns
function getSum_y(x, y, bit) {
    let sum = 0;
    while (y) {
        sum += bit[x][y];
        y -= (y & -y);
    }
    return sum;
}
 
// Method to calculate prefix sum of mat[x][y]
function getSum(x, y, bit) {
    let sum = 0;
    while (x) {
        sum += getSum_y(x, y, bit);
        x -= (x & -x);
    }
    return sum;
}
 
// Driver Code
 
// Number of rows and columns
let n = 3;
let mat = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0));
// Array to store 2D Fenwick tree
let bit = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0));
let queries = [
    [1, 2, 0, 2],
    [2, 0, 0, 2, 2],
    [1, 0, 0, 1],
    [2, 0, 0, 2, 0]
];
for (let query of queries) {
    // Point Update Query
    if (query[0] === 1) {
        let x = query[1] + 1;
        let y = query[2] + 1;
        let ele = query[3];
        update(x, y, ele - mat[x][y], bit, n);
        mat[x][y] = ele;
    }
    // Range Sum Query
    else {
        let x1 = query[1] + 1;
        let y1 = query[2] + 1;
        let x2 = query[3] + 1;
        let y2 = query[4] + 1;
        let bottomRight = getSum(x2, y2, bit);
        let topRight = getSum(x1 - 1, y2, bit);
        let bottomLeft = getSum(x2, y1 - 1, bit);
        let topLeft = getSum(x1 - 1, y1 - 1, bit);
        console.log(bottomRight - topRight - bottomLeft + topLeft + " ");
    }
}


Output

2 3 






Time Complexity: O((N * N + Q)*log(N)*log(N)), where N is the number of rows and columns in input matrix mat[][] and Q is the number of queries.

  • Both update(x, y, ele) function and getSum(x, y) function takes O(log(N)*log(N)) time.
  • Building the Binary Indexed Tree takes O(N * N * log(N)*log(N)) time.
  • Since in each of the queries we are calling getSum(x, y) function so answering all the Q queries takes O(Q*log(N)*log(N)) time.

So overall time complexity becomes O((N * N + Q)*log(N)*log(N)).

Auxiliary Space: O(N * N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads