Open In App

Two Dimensional Binary Indexed Tree or Fenwick Tree

Last Updated : 30 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Prerequisite – Fenwick Tree

We know that to answer range sum queries on a 1-D array efficiently, binary indexed tree (or Fenwick Tree) is the best choice (even better than segment tree due to less memory requirements and a little faster than segment tree).

Can we answer sub-matrix sum queries efficiently using Binary Indexed Tree ?

The answer is yes. This is possible using a 2D BIT which is nothing but an array of 1D BIT. 

Algorithm:

We consider the below example. Suppose we have to find the sum of all numbers inside the highlighted area:

fenwick tree

We assume the origin of the matrix at the bottom – O.Then a 2D BIT exploits the fact that-

Sum under the marked area = Sum(OB) - Sum(OD) - 
                            Sum(OA) + Sum(OC) 

In our program, we use the getSum(x, y) function which finds the sum of the matrix from (0, 0) to (x, y). 
Hence the below formula : 

Sum under the marked area = Sum(OB) - Sum(OD) - 
                            Sum(OA) + Sum(OC) 

The above formula gets reduced to,

Query(x1,y1,x2,y2) = getSum(x2, y2) - 
                     getSum(x2, y1-1) - 
                     getSum(x1-1, y2) + 
                     getSum(x1-1, y1-1) 

where, 
x1, y1 = x and y coordinates of C 
x2, y2 = x and y coordinates of B
The updateBIT(x, y, val) function updates all the elements under the region – (x, y) to (N, M) where, 
N = maximum X co-ordinate of the whole matrix. 
M = maximum Y co-ordinate of the whole matrix.
The rest procedure is quite similar to that of 1D Binary Indexed Tree.

Below is the C++ implementation of 2D indexed tree 

C++




/* C++ program to implement 2D Binary Indexed Tree
 
2D BIT is basically a BIT where each element is another BIT.
Updating by adding v on (x, y) means it's effect will be found
throughout the rectangle [(x, y), (max_x, max_y)],
and query for (x, y) gives you the result of the rectangle
[(0, 0), (x, y)], assuming the total rectangle is
[(0, 0), (max_x, max_y)]. So when you query and update on
this BIT,you have to be careful about how many times you are
subtracting a rectangle and adding it. Simple set union formula
works here.
 
So if you want to get the result of a specific rectangle
[(x1, y1), (x2, y2)], the following steps are necessary:
 
Query(x1,y1,x2,y2) = getSum(x2, y2)-getSum(x2, y1-1) -
                     getSum(x1-1, y2)+getSum(x1-1, y1-1)
 
Here 'Query(x1,y1,x2,y2)' means the sum of elements enclosed
in the rectangle with bottom-left corner's co-ordinates
(x1, y1) and top-right corner's co-ordinates - (x2, y2)
 
Constraints -> x1<=x2 and y1<=y2
 
    /\
 y  |
    |           --------(x2,y2)
    |          |       |
    |          |       |
    |          |       |
    |          ---------
    |       (x1,y1)
    |
    |___________________________
   (0, 0)                   x-->
 
In this program we have assumed a square matrix. The
program can be easily extended to a rectangular one. */
 
#include<bits/stdc++.h>
using namespace std;
 
#define N 4 // N-->max_x and max_y
 
// A structure to hold the queries
struct Query
{
    int x1, y1; // x and y co-ordinates of bottom left
    int x2, y2; // x and y co-ordinates of top right
};
 
// A function to update the 2D BIT
void updateBIT(int BIT[][N+1], int x, int y, int val)
{
    for (; x <= N; x += (x & -x))
    {
        // This loop update all the 1D BIT inside the
        // array of 1D BIT = BIT[x]
        for (int yy=y; yy <= N; yy += (yy & -yy))
            BIT[x][yy] += val;
    }
    return;
}
 
// A function to get sum from (0, 0) to (x, y)
int getSum(int BIT[][N+1], int x, int y)
{
    int sum = 0;
 
    for(; x > 0; x -= x&-x)
    {
        // This loop sum through all the 1D BIT
        // inside the array of 1D BIT = BIT[x]
        for(int yy=y; yy > 0; yy -= yy&-yy)
        {
            sum += BIT[x][yy];
        }
    }
    return sum;
}
 
// A function to create an auxiliary matrix
// from the given input matrix
void constructAux(int mat[][N], int aux[][N+1])
{
    // Initialise Auxiliary array to 0
    for (int i=0; i<=N; i++)
        for (int j=0; j<=N; j++)
            aux[i][j] = 0;
 
    // Construct the Auxiliary Matrix
    for (int j=1; j<=N; j++)
        for (int i=1; i<=N; i++)
            aux[i][j] = mat[N-j][i-1];
 
    return;
}
 
// A function to construct a 2D BIT
void construct2DBIT(int mat[][N], int BIT[][N+1])
{
    // Create an auxiliary matrix
    int aux[N+1][N+1];
    constructAux(mat, aux);
 
    // Initialise the BIT to 0
    for (int i=1; i<=N; i++)
        for (int j=1; j<=N; j++)
            BIT[i][j] = 0;
 
    for (int j=1; j<=N; j++)
    {
        for (int i=1; i<=N; i++)
        {
            // Creating a 2D-BIT using update function
            // everytime we/ encounter a value in the
            // input 2D-array
            int v1 = getSum(BIT, i, j);
            int v2 = getSum(BIT, i, j-1);
            int v3 = getSum(BIT, i-1, j-1);
            int v4 = getSum(BIT, i-1, j);
 
            // Assigning a value to a particular element
            // of 2D BIT
            updateBIT(BIT, i, j, aux[i][j]-(v1-v2-v4+v3));
        }
    }
 
    return;
}
 
// A function to answer the queries
void answerQueries(Query q[], int m, int BIT[][N+1])
{
    for (int i=0; i<m; i++)
    {
        int x1 = q[i].x1 + 1;
        int y1 = q[i].y1 + 1;
        int x2 = q[i].x2 + 1;
        int y2 = q[i].y2 + 1;
 
        int ans = getSum(BIT, x2, y2)-getSum(BIT, x2, y1-1)-
                  getSum(BIT, x1-1, y2)+getSum(BIT, x1-1, y1-1);
 
        printf ("Query(%d, %d, %d, %d) = %d\n",
                q[i].x1, q[i].y1, q[i].x2, q[i].y2, ans);
    }
    return;
}
 
// Driver program
int main()
{
    int mat[N][N] = {{1, 2, 3, 4},
                    {5, 3, 8, 1},
                    {4, 6, 7, 5},
                    {2, 4, 8, 9}};
 
    // Create a 2D Binary Indexed Tree
    int BIT[N+1][N+1];
    construct2DBIT(mat, BIT);
 
    /* Queries of the form - x1, y1, x2, y2
       For example the query- {1, 1, 3, 2} means the sub-matrix-
    y
    /\
 3  |       1 2 3 4      Sub-matrix
 2  |       5 3 8 1      {1,1,3,2}      --->     3 8 1
 1  |       4 6 7 5                                 6 7 5
 0  |       2 4 8 9
    |
  --|------ 0 1 2 3 ----> x
    |
 
    Hence sum of the sub-matrix = 3+8+1+6+7+5 = 30
 
    */
 
    Query q[] = {{1, 1, 3, 2}, {2, 3, 3, 3}, {1, 1, 1, 1}};
    int m = sizeof(q)/sizeof(q[0]);
 
    answerQueries(q, m, BIT);
 
    return(0);
}


Java




/* Java program to implement 2D Binary Indexed Tree
 
2D BIT is basically a BIT where each element is another BIT.
Updating by adding v on (x, y) means it's effect will be found
throughout the rectangle [(x, y), (max_x, max_y)],
and query for (x, y) gives you the result of the rectangle
[(0, 0), (x, y)], assuming the total rectangle is
[(0, 0), (max_x, max_y)]. So when you query and update on
this BIT,you have to be careful about how many times you are
subtracting a rectangle and adding it. Simple set union formula
works here.
 
So if you want to get the result of a specific rectangle
[(x1, y1), (x2, y2)], the following steps are necessary:
 
Query(x1,y1,x2,y2) = getSum(x2, y2)-getSum(x2, y1-1) -
                    getSum(x1-1, y2)+getSum(x1-1, y1-1)
 
Here 'Query(x1,y1,x2,y2)' means the sum of elements enclosed
in the rectangle with bottom-left corner's co-ordinates
(x1, y1) and top-right corner's co-ordinates - (x2, y2)
 
Constraints -> x1<=x2 and y1<=y2
 
    /\
y |
    |     --------(x2,y2)
    |     | |
    |     | |
    |     | |
    |     ---------
    | (x1,y1)
    |
    |___________________________
(0, 0)             x-->
 
In this program we have assumed a square matrix. The
program can be easily extended to a rectangular one. */
class GFG
{
static final int N = 4; // N-.max_x and max_y
 
// A structure to hold the queries
static class Query
{
    int x1, y1; // x and y co-ordinates of bottom left
    int x2, y2; // x and y co-ordinates of top right
 
        public Query(int x1, int y1, int x2, int y2)
        {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }
         
};
 
// A function to update the 2D BIT
static void updateBIT(int BIT[][], int x,
                      int y, int val)
{
    for (; x <= N; x += (x & -x))
    {
        // This loop update all the 1D BIT inside the
        // array of 1D BIT = BIT[x]
        for (; y <= N; y += (y & -y))
            BIT[x][y] += val;
    }
    return;
}
 
// A function to get sum from (0, 0) to (x, y)
static int getSum(int BIT[][], int x, int y)
{
    int sum = 0;
 
    for(; x > 0; x -= x&-x)
    {
        // This loop sum through all the 1D BIT
        // inside the array of 1D BIT = BIT[x]
        for(; y > 0; y -= y&-y)
        {
            sum += BIT[x][y];
        }
    }
    return sum;
}
 
// A function to create an auxiliary matrix
// from the given input matrix
static void constructAux(int mat[][], int aux[][])
{
    // Initialise Auxiliary array to 0
    for (int i = 0; i <= N; i++)
        for (int j = 0; j <= N; j++)
            aux[i][j] = 0;
 
    // Construct the Auxiliary Matrix
    for (int j = 1; j <= N; j++)
        for (int i = 1; i <= N; i++)
            aux[i][j] = mat[N - j][i - 1];
 
    return;
}
 
// A function to construct a 2D BIT
static void construct2DBIT(int mat[][],
                           int BIT[][])
{
    // Create an auxiliary matrix
    int [][]aux = new int[N + 1][N + 1];
    constructAux(mat, aux);
 
    // Initialise the BIT to 0
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            BIT[i][j] = 0;
 
    for (int j = 1; j <= N; j++)
    {
        for (int i = 1; i <= N; i++)
        {
            // Creating a 2D-BIT using update function
            // everytime we/ encounter a value in the
            // input 2D-array
            int v1 = getSum(BIT, i, j);
            int v2 = getSum(BIT, i, j - 1);
            int v3 = getSum(BIT, i - 1, j - 1);
            int v4 = getSum(BIT, i - 1, j);
 
            // Assigning a value to a particular element
            // of 2D BIT
            updateBIT(BIT, i, j, aux[i][j] -
                     (v1 - v2 - v4 + v3));
        }
    }
    return;
}
 
// A function to answer the queries
static void answerQueries(Query q[], int m, int BIT[][])
{
    for (int i = 0; i < m; i++)
    {
        int x1 = q[i].x1 + 1;
        int y1 = q[i].y1 + 1;
        int x2 = q[i].x2 + 1;
        int y2 = q[i].y2 + 1;
 
        int ans = getSum(BIT, x2, y2) -
                  getSum(BIT, x2, y1 - 1) -
                  getSum(BIT, x1 - 1, y2) +
                  getSum(BIT, x1 - 1, y1 - 1);
 
        System.out.printf("Query(%d, %d, %d, %d) = %d\n",
                q[i].x1, q[i].y1, q[i].x2, q[i].y2, ans);
    }
    return;
}
 
// Driver Code
public static void main(String[] args)
{
    int mat[][] = { {1, 2, 3, 4},
                    {5, 3, 8, 1},
                    {4, 6, 7, 5},
                    {2, 4, 8, 9} };
 
    // Create a 2D Binary Indexed Tree
    int [][]BIT = new int[N + 1][N + 1];
    construct2DBIT(mat, BIT);
 
    /* Queries of the form - x1, y1, x2, y2
    For example the query- {1, 1, 3, 2} means the sub-matrix-
        y
        /\
    3 | 1 2 3 4     Sub-matrix
    2 | 5 3 8 1     {1,1,3,2} --.     3 8 1
    1 | 4 6 7 5                                 6 7 5
    0 | 2 4 8 9
        |
    --|------ 0 1 2 3 ---. x
        |
     
        Hence sum of the sub-matrix = 3+8+1+6+7+5 = 30
    */
    Query q[] = {new Query(1, 1, 3, 2),
                 new Query(2, 3, 3, 3),
                 new Query(1, 1, 1, 1)};
    int m = q.length;
 
    answerQueries(q, m, BIT);
}
}
 
// This code is contributed by 29AjayKumar


Python3




'''Python3  program to implement 2D Binary Indexed Tree
   
2D BIT is basically a BIT where each element is another BIT.
Updating by adding v on (x, y) means it's effect will be found
throughout the rectangle [(x, y), (max_x, max_y)],
and query for (x, y) gives you the result of the rectangle
[(0, 0), (x, y)], assuming the total rectangle is
[(0, 0), (max_x, max_y)]. So when you query and update on
this BIT,you have to be careful about how many times you are
subtracting a rectangle and adding it. Simple set union formula
works here.
   
So if you want to get the result of a specific rectangle
[(x1, y1), (x2, y2)], the following steps are necessary:
   
Query(x1,y1,x2,y2) = getSum(x2, y2)-getSum(x2, y1-1) -
                    getSum(x1-1, y2)+getSum(x1-1, y1-1)
   
Here 'Query(x1,y1,x2,y2)' means the sum of elements enclosed
in the rectangle with bottom-left corner's co-ordinates
(x1, y1) and top-right corner's co-ordinates - (x2, y2)
   
Constraints -> x1<=x2 and y1<=y2
   
    /\
y |
    |     --------(x2,y2)
    |     | |
    |     | |
    |     | |
    |     ---------
    | (x1,y1)
    |
    |___________________________
(0, 0)             x-->
   
In this program we have assumed a square matrix. The
program can be easily extended to a rectangular one. '''
 
N = 4 # N-.max_x and max_y
 
# A structure to hold the queries
class Query:
 
    def __init__(self, x1,y1,x2,y2):
     
        self.x1 = x1;
        self.y1 = y1;
        self.x2 = x2;
        self.y2 = y2;
 
 
# A function to update the 2D BIT
def updateBIT(BIT,x,y,val):
     
    while x <= N:
     
        # This loop update all the 1D BIT inside the
        # array of 1D BIT = BIT[x]
        while y <= N:
            BIT[x][y] += val;
            y += (y & -y)
         
        x += (x & -x)
     
    return;
 
 
# A function to get sum from (0, 0) to (x, y)
def getSum(BIT,x,y):
 
    sum = 0;
     
    while x > 0:
        # This loop sum through all the 1D BIT
        # inside the array of 1D BIT = BIT[x]
        while y > 0:
 
            sum += BIT[x][y];
            y -= y&-y
         
        x -= x&-x
     
    return sum;
 
 
# A function to create an auxiliary matrix
# from the given input matrix
def constructAux(mat,aux):
    # Initialise Auxiliary array to 0
    for  i in range(N + 1):
        for j in range(N + 1):
            aux[i][j] = 0
   
    # Construct the Auxiliary Matrix
    for j in range(1, N + 1):
        for i in range(1, N + 1):
            aux[i][j] = mat[N - j][i - 1];
   
    return
 
 
# A function to construct a 2D BIT
def construct2DBIT(mat,BIT):
    # Create an auxiliary matrix
    aux = [None for i in range(N + 1)]
    for i in range(N + 1) :
     
        aux[i]= [None for i in range(N + 1)]
     
    constructAux(mat, aux)
   
    # Initialise the BIT to 0
    for i in range(1, N + 1):
        for j in range(1, N + 1):
            BIT[i][j] = 0;
   
    for j in range(1, N + 1):
     
        for i in range(1, N + 1):
         
            # Creating a 2D-BIT using update function
            # everytime we/ encounter a value in the
            # input 2D-array
            v1 = getSum(BIT, i, j);
            v2 = getSum(BIT, i, j - 1);
            v3 = getSum(BIT, i - 1, j - 1);
            v4 = getSum(BIT, i - 1, j);
   
            # Assigning a value to a particular element
            # of 2D BIT
            updateBIT(BIT, i, j, aux[i][j] -
                     (v1 - v2 - v4 + v3));
         
     
    return;
 
 
# A function to answer the queries
def answerQueries(q,m,BIT):
     
    for i in range(m):
      
        x1 = q[i].x1 + 1;
        y1 = q[i].y1 + 1;
        x2 = q[i].x2 + 1;
        y2 = q[i].y2 + 1;
   
        ans = getSum(BIT, x2, y2) - \
                  getSum(BIT, x2, y1 - 1) - \
                  getSum(BIT, x1 - 1, y2) + \
                  getSum(BIT, x1 - 1, y1 - 1);
   
        print("Query (", q[i].x1, ", ", q[i].y1, ", ", q[i].x2, ", " , q[i].y2, ") = " ,ans, sep = "")
     
    return;
 
 
# Driver Code
mat= [[1, 2, 3, 4],
                    [5, 3, 8, 1],
                    [4, 6, 7, 5],
                    [2, 4, 8, 9]];
   
# Create a 2D Binary Indexed Tree
BIT = [None for i in range(N + 1)]
for i in range(N + 1):
 
    BIT[i]= [None for i in range(N + 1)]
    for j in range(N + 1):
            BIT[i][j]=0
         
     
construct2DBIT(mat, BIT);
   
''' Queries of the form - x1, y1, x2, y2
    For example the query- {1, 1, 3, 2} means the sub-matrix-
        y
        /\
    3 | 1 2 3 4     Sub-matrix
    2 | 5 3 8 1     {1,1,3,2} --.     3 8 1
    1 | 4 6 7 5                                 6 7 5
    0 | 2 4 8 9
        |
    --|------ 0 1 2 3 ---. x
        |
       
        Hence sum of the sub-matrix = 3+8+1+6+7+5 = 30
     
    '''
q = [Query(1, 1, 3, 2), Query(2, 3, 3, 3), Query(1, 1, 1, 1)];
m = len(q)
   
answerQueries(q, m, BIT);
 
# This code is contributed by phasing17


C#




/* C# program to implement 2D Binary Indexed Tree
 
2D BIT is basically a BIT where each element is another BIT.
Updating by.Adding v on (x, y) means it's effect will be found
throughout the rectangle [(x, y), (max_x, max_y)],
and query for (x, y) gives you the result of the rectangle
[(0, 0), (x, y)], assuming the total rectangle is
[(0, 0), (max_x, max_y)]. So when you query and update on
this BIT,you have to be careful about how many times you are
subtracting a rectangle and.Adding it. Simple set union formula
works here.
 
So if you want to get the result of a specific rectangle
[(x1, y1), (x2, y2)], the following steps are necessary:
 
Query(x1,y1,x2,y2) = getSum(x2, y2)-getSum(x2, y1-1) -
                    getSum(x1-1, y2)+getSum(x1-1, y1-1)
 
Here 'Query(x1,y1,x2,y2)' means the sum of elements enclosed
in the rectangle with bottom-left corner's co-ordinates
(x1, y1) and top-right corner's co-ordinates - (x2, y2)
 
Constraints -> x1<=x2 and y1<=y2
 
    /\
y |
    |     --------(x2,y2)
    |     | |
    |     | |
    |     | |
    |     ---------
    | (x1,y1)
    |
    |___________________________
(0, 0)             x-->
 
In this program we have assumed a square matrix. The
program can be easily extended to a rectangular one. */
using System;
 
class GFG
{
static readonly int N = 4; // N-.max_x and max_y
 
// A structure to hold the queries
public class Query
{
    public int x1, y1; // x and y co-ordinates of bottom left
    public int x2, y2; // x and y co-ordinates of top right
 
        public Query(int x1, int y1, int x2, int y2)
        {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }
         
};
 
// A function to update the 2D BIT
static void updateBIT(int [,]BIT, int x,
                    int y, int val)
{
    for (; x <= N; x += (x & -x))
    {
        // This loop update all the 1D BIT inside the
        // array of 1D BIT = BIT[x]
        for (; y <= N; y += (y & -y))
            BIT[x,y] += val;
    }
    return;
}
 
// A function to get sum from (0, 0) to (x, y)
static int getSum(int [,]BIT, int x, int y)
{
    int sum = 0;
 
    for(; x > 0; x -= x&-x)
    {
        // This loop sum through all the 1D BIT
        // inside the array of 1D BIT = BIT[x]
        for(; y > 0; y -= y&-y)
        {
            sum += BIT[x, y];
        }
    }
    return sum;
}
 
// A function to create an auxiliary matrix
// from the given input matrix
static void constructAux(int [,]mat, int [,]aux)
{
    // Initialise Auxiliary array to 0
    for (int i = 0; i <= N; i++)
        for (int j = 0; j <= N; j++)
            aux[i, j] = 0;
 
    // Construct the Auxiliary Matrix
    for (int j = 1; j <= N; j++)
        for (int i = 1; i <= N; i++)
            aux[i, j] = mat[N - j, i - 1];
 
    return;
}
 
// A function to construct a 2D BIT
static void construct2DBIT(int [,]mat,
                        int [,]BIT)
{
    // Create an auxiliary matrix
    int [,]aux = new int[N + 1, N + 1];
    constructAux(mat, aux);
 
    // Initialise the BIT to 0
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            BIT[i, j] = 0;
 
    for (int j = 1; j <= N; j++)
    {
        for (int i = 1; i <= N; i++)
        {
            // Creating a 2D-BIT using update function
            // everytime we/ encounter a value in the
            // input 2D-array
            int v1 = getSum(BIT, i, j);
            int v2 = getSum(BIT, i, j - 1);
            int v3 = getSum(BIT, i - 1, j - 1);
            int v4 = getSum(BIT, i - 1, j);
 
            // Assigning a value to a particular element
            // of 2D BIT
            updateBIT(BIT, i, j, aux[i,j] -
                    (v1 - v2 - v4 + v3));
        }
    }
    return;
}
 
// A function to answer the queries
static void answerQueries(Query []q, int m, int [,]BIT)
{
    for (int i = 0; i < m; i++)
    {
        int x1 = q[i].x1 + 1;
        int y1 = q[i].y1 + 1;
        int x2 = q[i].x2 + 1;
        int y2 = q[i].y2 + 1;
 
        int ans = getSum(BIT, x2, y2) -
                getSum(BIT, x2, y1 - 1) -
                getSum(BIT, x1 - 1, y2) +
                getSum(BIT, x1 - 1, y1 - 1);
 
        Console.Write("Query({0}, {1}, {2}, {3}) = {4}\n",
                q[i].x1, q[i].y1, q[i].x2, q[i].y2, ans);
    }
    return;
}
 
// Driver Code
public static void Main(String[] args)
{
    int [,]mat = { {1, 2, 3, 4},
                    {5, 3, 8, 1},
                    {4, 6, 7, 5},
                    {2, 4, 8, 9} };
 
    // Create a 2D Binary Indexed Tree
    int [,]BIT = new int[N + 1,N + 1];
    construct2DBIT(mat, BIT);
 
    /* Queries of the form - x1, y1, x2, y2
    For example the query- {1, 1, 3, 2} means the sub-matrix-
        y
        /\
    3 | 1 2 3 4     Sub-matrix
    2 | 5 3 8 1     {1,1,3,2} --.     3 8 1
    1 | 4 6 7 5                                 6 7 5
    0 | 2 4 8 9
        |
    --|------ 0 1 2 3 ---. x
        |
     
        Hence sum of the sub-matrix = 3+8+1+6+7+5 = 30
    */
    Query []q = {new Query(1, 1, 3, 2),
                new Query(2, 3, 3, 3),
                new Query(1, 1, 1, 1)};
    int m = q.Length;
 
    answerQueries(q, m, BIT);
}
}
 
// This code is contributed by Rajput-Ji


Javascript




<script>
/* Javascript program to implement 2D Binary Indexed Tree
   
2D BIT is basically a BIT where each element is another BIT.
Updating by adding v on (x, y) means it's effect will be found
throughout the rectangle [(x, y), (max_x, max_y)],
and query for (x, y) gives you the result of the rectangle
[(0, 0), (x, y)], assuming the total rectangle is
[(0, 0), (max_x, max_y)]. So when you query and update on
this BIT,you have to be careful about how many times you are
subtracting a rectangle and adding it. Simple set union formula
works here.
   
So if you want to get the result of a specific rectangle
[(x1, y1), (x2, y2)], the following steps are necessary:
   
Query(x1,y1,x2,y2) = getSum(x2, y2)-getSum(x2, y1-1) -
                    getSum(x1-1, y2)+getSum(x1-1, y1-1)
   
Here 'Query(x1,y1,x2,y2)' means the sum of elements enclosed
in the rectangle with bottom-left corner's co-ordinates
(x1, y1) and top-right corner's co-ordinates - (x2, y2)
   
Constraints -> x1<=x2 and y1<=y2
   
    /\
y |
    |     --------(x2,y2)
    |     | |
    |     | |
    |     | |
    |     ---------
    | (x1,y1)
    |
    |___________________________
(0, 0)             x-->
   
In this program we have assumed a square matrix. The
program can be easily extended to a rectangular one. */
 
let N = 4; // N-.max_x and max_y
 
// A structure to hold the queries
class Query
{
    constructor(x1,y1,x2,y2)
    {
        this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
    }
}
 
// A function to update the 2D BIT
function updateBIT(BIT,x,y,val)
{
    for (; x <= N; x += (x & -x))
    {
        // This loop update all the 1D BIT inside the
        // array of 1D BIT = BIT[x]
        for (; y <= N; y += (y & -y))
            BIT[x][y] += val;
    }
    return;
}
 
// A function to get sum from (0, 0) to (x, y)
function getSum(BIT,x,y)
{
    let sum = 0;
   
    for(; x > 0; x -= x&-x)
    {
        // This loop sum through all the 1D BIT
        // inside the array of 1D BIT = BIT[x]
        for(; y > 0; y -= y&-y)
        {
            sum += BIT[x][y];
        }
    }
    return sum;
}
 
// A function to create an auxiliary matrix
// from the given input matrix
function constructAux(mat,aux)
{
    // Initialise Auxiliary array to 0
    for (let i = 0; i <= N; i++)
        for (let j = 0; j <= N; j++)
            aux[i][j] = 0;
   
    // Construct the Auxiliary Matrix
    for (let j = 1; j <= N; j++)
        for (let i = 1; i <= N; i++)
            aux[i][j] = mat[N - j][i - 1];
   
    return;
}
 
// A function to construct a 2D BIT
function construct2DBIT(mat,BIT)
{
    // Create an auxiliary matrix
    let aux = new Array(N + 1);
    for(let i=0;i<(N+1);i++)
    {
        aux[i]=new Array(N+1);
    }
    constructAux(mat, aux);
   
    // Initialise the BIT to 0
    for (let i = 1; i <= N; i++)
        for (let j = 1; j <= N; j++)
            BIT[i][j] = 0;
   
    for (let j = 1; j <= N; j++)
    {
        for (let i = 1; i <= N; i++)
        {
            // Creating a 2D-BIT using update function
            // everytime we/ encounter a value in the
            // input 2D-array
            let v1 = getSum(BIT, i, j);
            let v2 = getSum(BIT, i, j - 1);
            let v3 = getSum(BIT, i - 1, j - 1);
            let v4 = getSum(BIT, i - 1, j);
   
            // Assigning a value to a particular element
            // of 2D BIT
            updateBIT(BIT, i, j, aux[i][j] -
                     (v1 - v2 - v4 + v3));
        }
    }
    return;
}
 
// A function to answer the queries
function answerQueries(q,m,BIT)
{
    for (let i = 0; i < m; i++)
    {
        let x1 = q[i].x1 + 1;
        let y1 = q[i].y1 + 1;
        let x2 = q[i].x2 + 1;
           let y2 = q[i].y2 + 1;
   
        let ans = getSum(BIT, x2, y2) -
                  getSum(BIT, x2, y1 - 1) -
                  getSum(BIT, x1 - 1, y2) +
                  getSum(BIT, x1 - 1, y1 - 1);
   
        document.write("Query ("+q[i].x1+", " +q[i].y1+", " +q[i].x2+", " +q[i].y2+") = " +ans+"<br>");
    }
    return;
}
 
// Driver Code
let mat= [[1, 2, 3, 4],
                    [5, 3, 8, 1],
                    [4, 6, 7, 5],
                    [2, 4, 8, 9]];
   
    // Create a 2D Binary Indexed Tree
    let BIT = new Array(N + 1);
    for(let i=0;i<(N+1);i++)
    {
        BIT[i]=new Array(N+1);
        for(let j=0;j<(N+1);j++)
        {
            BIT[i][j]=0;
        }
    }
    construct2DBIT(mat, BIT);
   
    /* Queries of the form - x1, y1, x2, y2
    For example the query- {1, 1, 3, 2} means the sub-matrix-
        y
        /\
    3 | 1 2 3 4     Sub-matrix
    2 | 5 3 8 1     {1,1,3,2} --.     3 8 1
    1 | 4 6 7 5                                 6 7 5
    0 | 2 4 8 9
        |
    --|------ 0 1 2 3 ---. x
        |
       
        Hence sum of the sub-matrix = 3+8+1+6+7+5 = 30
    */
    let q = [new Query(1, 1, 3, 2),
                 new Query(2, 3, 3, 3),
                 new Query(1, 1, 1, 1)];
    let m = q.length;
   
    answerQueries(q, m, BIT);
 
 
// This code is contributed by rag2127
</script>


Output

Query(1, 1, 3, 2) = 30
Query(2, 3, 3, 3) = 7
Query(1, 1, 1, 1) = 6

Time Complexity: 

  • Both updateBIT(x, y, val) function and getSum(x, y) function takes O(log(N)*log(M)) time.
  • Building the 2D BIT takes O(NM log(N)*log(M)).
  • 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(M)) time.
  • Hence the overall time complexity of the program is O((NM+Q)*log(N)*log(M)) where, 
    N = maximum X co-ordinate of the whole matrix. 
    M = maximum Y co-ordinate of the whole matrix. 
    Q = Number of queries.

Auxiliary Space: O(NM) to store the BIT and the auxiliary array



Similar Reads

Binary Indexed Tree/Fenwick Tree meaning in DSA
Binary Indexed Tree (BIT), also known as Fenwick Tree, is a data structure used for efficiently querying and updating cumulative frequency tables, or prefix sums. A Fenwick Tree is a complete binary tree, where each node represents a range of elements in an array and stores the sum of the elements in that range. Below is a simple structure of a Bin
3 min read
Fenwick Tree (Binary Indexed Tree) for Competitive Programming
In the world of competitive programming, speed is everything. Fenwick Tree (also known as Binary Indexed Tree), created by Peter M. Fenwick. They're like secret weapons for programmers, especially when you need to quickly find cumulative frequencies in problem-solving. This article breaks down Fenwick Trees in simple terms—how they're built and why
15+ min read
Difference Between one-dimensional and two-dimensional array
Array is a data structure that is used to store variables that are of similar data types at contiguous locations. The main advantage of the array is random access and cache friendliness. There are mainly three types of the array: One Dimensional (1D) ArrayTwo Dimension (2D) ArrayMultidimensional Array One Dimensional Array: It is a list of the vari
3 min read
Bitwise XOR of same indexed array elements after rearranging an array to make XOR of same indexed elements of two arrays equal
Given two arrays A[] and B[] consisting of N positive integers, the task is to the Bitwise XOR of same indexed array elements after rearranging the array B[] such that the Bitwise XOR of the same indexed elements of the arrays A[] becomes equal. Examples: Input: A[] = {1, 2, 3}, B[] = {4, 6, 7}Output: 5Explanation:Below are the possible arrangement
14 min read
Comparison between Fenwick Tree vs Segment Tree - with Similarities and Differences
Fenwick Tree (Binary Indexed Tree) and Segment Tree are both data structures used for efficient range query and update operations on an array. Here's a tabular comparison of these two data structures. Similarities between the Fenwick tree and Segment treeHere are some of the areas where Fenwick Tree is similar to Segment Tree: Array type: Both Fenw
2 min read
Order statistic tree using fenwick tree (BIT)
Given an array of integers with limited range (0 to 1000000). We need to implement an Order statistic tree using fenwick tree. It should support four operations: Insert, Delete, Select and Rank. Here n denotes the size of Fenwick tree and q denotes number of queries. Each query should be one of the following 4 operations. insertElement(x) - Insert
9 min read
XOR of elements in a given range with updates using Fenwick Tree
Given an array A[] of integers and array Q consisting of queries of the following two types: (1, L, R) : Return XOR of all elements present between indices L and R.(2, I, val) : update A[I] to A[I] XOR val. The task is to solve each query and print the XOR for every Query of 1st type, using Fenwick Tree.Examples: Input: A[] = {2, 1, 1, 3, 2, 3, 4,
13 min read
Queries to find the Lower Bound of K from Prefix Sum Array with updates using Fenwick Tree
Given an array A[ ] consisting of non-negative integers and a matrix Q[ ][ ] consisting of queries of the following two types: (1, l, val): Update A[l] to A[l] + val.(2, K): Find the lower_bound of K in the prefix sum array of A[ ]. If the lower_bound does not exist, print -1. The task for each query of the second type is to print the index of the
14 min read
Number of elements greater than K in the range L to R using Fenwick Tree (Offline queries)
Prerequisites: Fenwick Tree (Binary Indexed Tree)Given an array of N numbers, and a number of queries where each query will contain three numbers(l, r and k). The task is to calculate the number of array elements that are greater than K in the subarray[L, R]. Examples: Input: n=6 q=2 arr[ ] = { 7, 3, 9, 13, 5, 4 } Query1: l=1, r=4, k=6 Query2: l=2,
15+ min read
Searching in Binary Indexed Tree using Binary Lifting in O(LogN)
Binary Indexed Tree (BIT) is a data structure that allows efficient queries of a range of elements in an array and updates on individual elements in O(log n) time complexity, where n is the number of elements in the array. Binary Lifting:One of the efficient techniques used to perform search operations in BIT is called Binary lifting.Binary Lifting
9 min read
three90RightbarBannerImg