Binary Indexed Tree : Range Updates and Point Queries
Last Updated :
10 Mar, 2023
Given an array arr[0..n-1]. The following operations need to be performed.
- update(l, r, val): Add ‘val’ to all the elements in the array from [l, r].
- getElement(i): Find element in the array indexed at ‘i’.
Initially all the elements in the array are 0. Queries can be in any order, i.e., there can be many updates before point query.
Example:
Input: arr = {0, 0, 0, 0, 0}
Queries: update : l = 0, r = 4, val = 2
getElement : i = 3
update : l = 3, r = 4, val = 3
getElement : i = 3
Output: Element at 3 is 2
Element at 3 is 5
Explanation: Array after first update becomes
{2, 2, 2, 2, 2}
Array after second update becomes
{2, 2, 2, 5, 5}
Method 1 [update : O(n), getElement() : O(1)]
- update(l, r, val): Iterate over the subarray from l to r and increase all the elements by val.
- getElement(i): To get the element at i’th index, simply return arr[i].
The time complexity in the worst case is O(q*n) where q is the number of queries and n is the number of elements.
Method 2 [update: O(1), getElement(): O(n)]
We can avoid updating all elements and can update only 2 indexes of the array!
- update(l, r, val) : Add ‘val’ to the lth element and subtract ‘val’ from the (r+1)th element, do this for all the update queries.
arr[l] = arr[l] + val
arr[r+1] = arr[r+1] - val
- getElement(i) : To get ith element in the array find the sum of all integers in the array from 0 to i.(Prefix Sum).
Let’s analyze the update query. Why to add val to lth index? Adding val to lth index means that all the elements after l are increased by val, since we will be computing the prefix sum for every element. Why to subtract val from (r+1)th index? A range update was required from [l,r] but what we have updated is [l, n-1] so we need to remove val from all the elements after r i.e., subtract val from (r+1)th index. Thus the val is added to range [l,r]. Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
void update( int arr[], int l, int r, int val)
{
arr[l] += val;
arr[r+1] -= val;
}
int getElement( int arr[], int i)
{
int res = 0;
for ( int j = 0 ; j <= i; j++)
res += arr[j];
return res;
}
int main()
{
int arr[] = {0, 0, 0, 0, 0};
int n = sizeof (arr) / sizeof (arr[0]);
int l = 2, r = 4, val = 2;
update(arr, l, r, val);
int index = 4;
cout << "Element at index " << index << " is " <<
getElement(arr, index) << endl;
l = 0, r = 3, val = 4;
update(arr,l,r,val);
index = 3;
cout << "Element at index " << index << " is " <<
getElement(arr, index) << endl;
return 0;
}
|
Java
class GfG {
static void update( int arr[], int l, int r, int val)
{
arr[l] += val;
if (r + 1 < arr.length)
arr[r+ 1 ] -= val;
}
static int getElement( int arr[], int i)
{
int res = 0 ;
for ( int j = 0 ; j <= i; j++)
res += arr[j];
return res;
}
public static void main(String[] args)
{
int arr[] = { 0 , 0 , 0 , 0 , 0 };
int n = arr.length;
int l = 2 , r = 4 , val = 2 ;
update(arr, l, r, val);
int index = 4 ;
System.out.println( "Element at index " + index + " is " +getElement(arr, index));
l = 0 ;
r = 3 ;
val = 4 ;
update(arr,l,r,val);
index = 3 ;
System.out.println( "Element at index " + index + " is " +getElement(arr, index));
}
}
|
Python3
def update(arr, l, r, val):
arr[l] + = val
if r + 1 < len (arr):
arr[r + 1 ] - = val
def getElement(arr, i):
res = 0
for j in range (i + 1 ):
res + = arr[j]
return res
if __name__ = = '__main__' :
arr = [ 0 , 0 , 0 , 0 , 0 ]
n = len (arr)
l = 2
r = 4
val = 2
update(arr, l, r, val)
index = 4
print ( "Element at index" , index,
"is" , getElement(arr, index))
l = 0
r = 3
val = 4
update(arr, l, r, val)
index = 3
print ( "Element at index" , index,
"is" , getElement(arr, index))
|
C#
using System;
class GfG
{
static void update( int []arr, int l,
int r, int val)
{
arr[l] += val;
if (r + 1 < arr.Length)
arr[r + 1] -= val;
}
static int getElement( int []arr, int i)
{
int res = 0;
for ( int j = 0 ; j <= i; j++)
res += arr[j];
return res;
}
public static void Main(String[] args)
{
int []arr = {0, 0, 0, 0, 0};
int n = arr.Length;
int l = 2, r = 4, val = 2;
update(arr, l, r, val);
int index = 4;
Console.WriteLine( "Element at index " +
index + " is " +
getElement(arr, index));
l = 0;
r = 3;
val = 4;
update(arr,l,r,val);
index = 3;
Console.WriteLine( "Element at index " +
index + " is " +
getElement(arr, index));
}
}
|
PHP
<?php
function update(& $arr , $l , $r , $val )
{
$arr [ $l ] += $val ;
if ( $r + 1 < sizeof( $arr ))
$arr [ $r + 1] -= $val ;
}
function getElement(& $arr , $i )
{
$res = 0;
for ( $j = 0 ; $j <= $i ; $j ++)
$res += $arr [ $j ];
return $res ;
}
$arr = array (0, 0, 0, 0, 0);
$n = sizeof( $arr );
$l = 2; $r = 4; $val = 2;
update( $arr , $l , $r , $val );
$index = 4;
echo ( "Element at index " . $index .
" is " . getElement( $arr , $index ) . "\n" );
$l = 0;
$r = 3;
$val = 4;
update( $arr , $l , $r , $val );
$index = 3;
echo ( "Element at index " . $index .
" is " . getElement( $arr , $index ));
?>
|
Javascript
function update(arr, l, r, val)
{
arr[l] += val;
arr[r+1] -= val;
}
function getElement(rr, i)
{
let res = 0;
for (let j = 0 ; j <= i; j++)
res += arr[j];
return res;
}
let arr = [0, 0, 0, 0, 0];
let n = arr.length;
let l = 2, r = 4, val = 2;
update(arr, l, r, val);
let index = 4;
console.log( "Element at index " ,index, " is " ,getElement(arr, index));
l = 0, r = 3, val = 4;
update(arr,l,r,val);
index = 3;
console.log( "Element at index " ,index, " is " ,getElement(arr, index));
|
Output:
Element at index 4 is 2
Element at index 3 is 6
Time complexity : O(q*n) where q is number of queries.
Auxiliary Space: O(n)
Method 3 (Using Binary Indexed Tree)
In method 2, we have seen that the problem can reduced to update and prefix sum queries. We have seen that BIT can be used to do update and prefix sum queries in O(Logn) time. Below is the implementation.
C++
#include <bits/stdc++.h>
using namespace std;
void updateBIT( int BITree[], int n, int index, int val)
{
index = index + 1;
while (index <= n)
{
BITree[index] += val;
index += index & (-index);
}
}
int *constructBITree( int arr[], int n)
{
int *BITree = new int [n+1];
for ( int i=1; i<=n; i++)
BITree[i] = 0;
for ( int i=0; i<n; i++)
updateBIT(BITree, n, i, arr[i]);
return BITree;
}
int getSum( int BITree[], int index)
{
int sum = 0;
index = index + 1;
while (index>0)
{
sum += BITree[index];
index -= index & (-index);
}
return sum;
}
void update( int BITree[], int l, int r, int n, int val)
{
updateBIT(BITree, n, l, val);
updateBIT(BITree, n, r+1, -val);
}
int main()
{
int arr[] = {0, 0, 0, 0, 0};
int n = sizeof (arr)/ sizeof (arr[0]);
int *BITree = constructBITree(arr, n);
int l = 2, r = 4, val = 2;
update(BITree, l, r, n, val);
int index = 4;
cout << "Element at index " << index << " is " <<
getSum(BITree,index) << "\n" ;
l = 0, r = 3, val = 4;
update(BITree, l, r, n, val);
index = 3;
cout << "Element at index " << index << " is " <<
getSum(BITree,index) << "\n" ;
return 0;
}
|
Java
class GFG
{
final static int MAX = 1000 ;
static int BITree[] = new int [MAX];
public static void updateBIT( int n,
int index,
int val)
{
index = index + 1 ;
while (index <= n)
{
BITree[index] += val;
index += index & (-index);
}
}
public static void constructBITree( int arr[],
int n)
{
for ( int i = 1 ; i <= n; i++)
BITree[i] = 0 ;
for ( int i = 0 ; i < n; i++)
updateBIT(n, i, arr[i]);
}
public static int getSum( int index)
{
int sum = 0 ;
index = index + 1 ;
while (index > 0 )
{
sum += BITree[index];
index -= index & (-index);
}
return sum;
}
public static void update( int l, int r,
int n, int val)
{
updateBIT(n, l, val);
updateBIT(n, r + 1 , -val);
}
public static void main(String args[])
{
int arr[] = { 0 , 0 , 0 , 0 , 0 };
int n = arr.length;
constructBITree(arr,n);
int l = 2 , r = 4 , val = 2 ;
update(l, r, n, val);
int index = 4 ;
System.out.println( "Element at index " +
index + " is " +
getSum(index));
l = 0 ; r = 3 ; val = 4 ;
update(l, r, n, val);
index = 3 ;
System.out.println( "Element at index " +
index + " is " +
getSum(index));
}
}
|
Python3
def updateBIT(BITree, n, index, val):
index = index + 1
while (index < = n):
BITree[index] + = val
index + = index & ( - index)
def constructBITree(arr, n):
BITree = [ 0 ] * (n + 1 )
for i in range (n):
updateBIT(BITree, n, i, arr[i])
return BITree
def getSum(BITree, index):
sum = 0
index = index + 1
while (index > 0 ):
sum + = BITree[index]
index - = index & ( - index)
return sum
def update(BITree, l, r, n, val):
updateBIT(BITree, n, l, val)
updateBIT(BITree, n, r + 1 , - val)
arr = [ 0 , 0 , 0 , 0 , 0 ]
n = len (arr)
BITree = constructBITree(arr, n)
l = 2
r = 4
val = 2
update(BITree, l, r, n, val)
index = 4
print ( "Element at index" , index, "is" , getSum(BITree, index))
l = 0
r = 3
val = 4
update(BITree, l, r, n, val)
index = 3
print ( "Element at index" , index, "is" , getSum(BITree,index))
|
C#
using System;
public class GFG
{
public const int MAX = 1000;
public static int [] BITree = new int [MAX];
public static void updateBIT( int n, int index, int val)
{
index = index + 1;
while (index <= n)
{
BITree[index] += val;
index += index & (-index);
}
}
public static void constructBITree( int [] arr, int n)
{
for ( int i = 1; i <= n; i++)
{
BITree[i] = 0;
}
for ( int i = 0; i < n; i++)
{
updateBIT(n, i, arr[i]);
}
}
public static int getSum( int index)
{
int sum = 0;
index = index + 1;
while (index > 0)
{
sum += BITree[index];
index -= index & (-index);
}
return sum;
}
public static void update( int l, int r, int n, int val)
{
updateBIT(n, l, val);
updateBIT(n, r + 1, -val);
}
public static void Main( string [] args)
{
int [] arr = new int [] {0, 0, 0, 0, 0};
int n = arr.Length;
constructBITree(arr,n);
int l = 2, r = 4, val = 2;
update(l, r, n, val);
int index = 4;
Console.WriteLine( "Element at index " + index + " is " + getSum(index));
l = 0;
r = 3;
val = 4;
update(l, r, n, val);
index = 3;
Console.WriteLine( "Element at index " + index + " is " + getSum(index));
}
}
|
Javascript
function updateBIT(BITree, n, index, val) {
index = index + 1;
while (index <= n) {
BITree[index] += val;
index += index & (-index);
}
}
function constructBITree(arr, n) {
let BITree = new Array(n+1).fill(0);
for (let i = 0; i < n; i++) {
updateBIT(BITree, n, i, arr[i]);
}
return BITree;
}
function getSum(BITree, index) {
let sum = 0;
index = index + 1;
while (index > 0) {
sum += BITree[index];
index -= index & (-index);
}
return sum;
}
function update(BITree, l, r, n, val) {
updateBIT(BITree, n, l, val);
updateBIT(BITree, n, r+1, -val);
}
let arr = [0, 0, 0, 0, 0];
let n = arr.length;
let BITree = constructBITree(arr, n);
let l = 2, r = 4, val = 2;
update(BITree, l, r, n, val);
let index = 4;
console.log(`Element at index ${index} is ${getSum(BITree,index)}`);
l = 0, r = 3, val = 4;
update(BITree, l, r, n, val);
index = 3;
console.log(`Element at index ${index} is ${getSum(BITree,index)}`);
|
Output:
Element at index 4 is 2
Element at index 3 is 6
Time Complexity : O(q * log n) + O(n * log n) where q is number of queries.
Auxiliary Space: O(n)
Method 1 is efficient when most of the queries are getElement(), method 2 is efficient when most of the queries are updates() and method 3 is preferred when there is mix of both queries.
Please Login to comment...