Queries to find the Lower Bound of K from Prefix Sum Array with updates using Fenwick Tree
Last Updated :
27 Sep, 2021
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 lower_bound of value K.
Examples:
Input: A[ ] = {1, 2, 3, 5, 8}, Q[ ][ ] = {{1, 0, 2}, {2, 5}, {1, 3, 5}}
Output: 1
Explanation:
Query 1: Update A[0] to A[0] + 2. Now A[ ] = {3, 2, 3, 5, 8}
Query 2: lower_bound of K = 5 in the prefix sum array {3, 5, 8, 13, 21} is 5 and index = 1.
Query 3: Update A[3] to A[3] + 5. Now A[ ] = {3, 2, 3, 10, 8}
Input: A[ ] = {4, 1, 12, 8, 20}, Q[ ] = {{2, 50}, {1, 3, 12}, {2, 50}}
Output: -1
Naive approach:
The simplest approach is to first build a prefix sum array of a given array A[ ], and for queries of Type 1, update values and recalculate the prefix sum. For query of Type 2, perform a Binary Search on the prefix sum array to find the lower bound.
Time Complexity: O(Q*(N*logn))
Auxiliary Space: O(N)
Efficient Approach:
The above approach can be optimized Fenwick Tree. Using this Data Structure, the update queries in the prefix sum array can be performed in logarithmic time.
Follow the steps below to solve the problem:
- Construct the Prefix Sum Array using Fenwick Tree.
- For queries of Type 1, while l > 0, add val to A[l] traverse to the parent node by adding the least significant bit in l.
- For queries of Type 2, perform the Binary Search on the Fenwick Tree to obtain the lower bound.
- Whenever a prefix sum greater than K appears, store that index and traverse the left part of the Fenwick Tree. Otherwise, traverse the right part of the Fenwick Tree now, perform Binary Search.
- Finally, print the required index.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int getSum( int BITree[], int index)
{
int ans = 0;
index += 1;
while (index > 0)
{
ans += BITree[index];
index -= index & (-index);
}
return ans;
}
static 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 = 0; i <= n; i++)
BITree[i] = 0;
for ( int i = 0; i < n; i++)
updateBIT(BITree, n, i, arr[i]);
return BITree;
}
int getLowerBound( int BITree[], int arr[],
int n, int k)
{
int lb = -1;
int l = 0, r = n - 1;
while (l <= r)
{
int mid = l + (r - l) / 2;
if (getSum(BITree, mid) >= k)
{
r = mid - 1;
lb = mid;
}
else
l = mid + 1;
}
return lb;
}
void performQueries( int A[], int n, int q[][3])
{
int * BITree = constructBITree(A, n);
for ( int i = 0;
i < sizeof (q[0]) / sizeof ( int );
i++)
{
int id = q[i][0];
if (id == 1)
{
int idx = q[i][1];
int val = q[i][2];
A[idx] += val;
updateBIT(BITree, n, idx, val);
}
else
{
int k = q[i][1];
int lb = getLowerBound(BITree,
A, n, k);
cout << lb << endl;
}
}
}
int main()
{
int A[] = { 1, 2, 3, 5, 8 };
int n = sizeof (A) / sizeof ( int );
int q[][3] = { { 1, 0, 2 },
{ 2, 5, 0 },
{ 1, 3, 5 } };
performQueries(A, n, q);
}
|
Java
import java.util.*;
import java.io.*;
class GFG {
static int getSum( int BITree[],
int index)
{
int ans = 0 ;
index += 1 ;
while (index > 0 ) {
ans += BITree[index];
index -= index & (-index);
}
return ans;
}
static void updateBIT( int BITree[],
int n, int index, int val)
{
index = index + 1 ;
while (index <= n) {
BITree[index] += val;
index += index & (-index);
}
}
static int [] constructBITree(
int arr[], int n)
{
int [] BITree = new int [n + 1 ];
for ( int i = 0 ; i <= n; i++)
BITree[i] = 0 ;
for ( int i = 0 ; i < n; i++)
updateBIT(BITree, n, i, arr[i]);
return BITree;
}
static int getLowerBound( int BITree[],
int [] arr, int n, int k)
{
int lb = - 1 ;
int l = 0 , r = n - 1 ;
while (l <= r) {
int mid = l + (r - l) / 2 ;
if (getSum(BITree, mid) >= k) {
r = mid - 1 ;
lb = mid;
}
else
l = mid + 1 ;
}
return lb;
}
static void performQueries( int A[], int n, int q[][])
{
int [] BITree = constructBITree(A, n);
for ( int i = 0 ; i < q.length; i++) {
int id = q[i][ 0 ];
if (id == 1 ) {
int idx = q[i][ 1 ];
int val = q[i][ 2 ];
A[idx] += val;
updateBIT(BITree, n, idx, val);
}
else {
int k = q[i][ 1 ];
int lb = getLowerBound(
BITree, A, n, k);
System.out.println(lb);
}
}
}
public static void main(String[] args)
{
int A[] = { 1 , 2 , 3 , 5 , 8 };
int n = A.length;
int [][] q = { { 1 , 0 , 2 },
{ 2 , 5 },
{ 1 , 3 , 5 } };
performQueries(A, n, q);
}
}
|
Python3
def getSum(BITree, index):
ans = 0
index + = 1
while (index > 0 ):
ans + = BITree[index]
index - = index & ( - index)
return ans
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 + 1 ):
BITree[i] = 0
for i in range (n):
updateBIT(BITree, n, i, arr[i])
return BITree
def getLowerBound(BITree, arr,
n, k):
lb = - 1
l = 0
r = n - 1
while (l < = r):
mid = l + (r - l) / / 2
if (getSum(BITree,
mid) > = k):
r = mid - 1
lb = mid
else :
l = mid + 1
return lb
def performQueries(A, n, q):
BITree = constructBITree(A, n)
for i in range ( len (q)):
id = q[i][ 0 ]
if ( id = = 1 ):
idx = q[i][ 1 ]
val = q[i][ 2 ]
A[idx] + = val
updateBIT(BITree, n,
idx, val)
else :
k = q[i][ 1 ]
lb = getLowerBound(BITree,
A, n, k)
print (lb)
if __name__ = = "__main__" :
A = [ 1 , 2 , 3 , 5 , 8 ]
n = len (A)
q = [[ 1 , 0 , 2 ],
[ 2 , 5 , 0 ],
[ 1 , 3 , 5 ]]
performQueries(A, n, q)
|
C#
using System;
class GFG{
static int getSum( int []BITree,
int index)
{
int ans = 0;
index += 1;
while (index > 0)
{
ans += BITree[index];
index -= index & (-index);
}
return ans;
}
static void updateBIT( int []BITree,
int n, int index,
int val)
{
index = index + 1;
while (index <= n)
{
BITree[index] += val;
index += index & (-index);
}
}
static int [] constructBITree( int []arr,
int n)
{
int [] BITree = new int [n + 1];
for ( int i = 0; i <= n; i++)
BITree[i] = 0;
for ( int i = 0; i < n; i++)
updateBIT(BITree, n, i, arr[i]);
return BITree;
}
static int getLowerBound( int []BITree,
int [] arr, int n,
int k)
{
int lb = -1;
int l = 0, r = n - 1;
while (l <= r)
{
int mid = l + (r - l) / 2;
if (getSum(BITree, mid) >= k)
{
r = mid - 1;
lb = mid;
}
else
l = mid + 1;
}
return lb;
}
static void performQueries( int []A, int n,
int [,]q)
{
int [] BITree = constructBITree(A, n);
for ( int i = 0; i < q.GetLength(0); i++)
{
int id = q[i, 0];
if (id == 1)
{
int idx = q[i, 1];
int val = q[i, 2];
A[idx] += val;
updateBIT(BITree, n, idx, val);
}
else
{
int k = q[i, 1];
int lb = getLowerBound(BITree,
A, n, k);
Console.WriteLine(lb);
}
}
}
public static void Main(String[] args)
{
int []A = { 1, 2, 3, 5, 8 };
int n = A.Length;
int [,]q = { { 1, 0, 2 },
{ 2, 5, 0 },
{ 1, 3, 5 } };
performQueries(A, n, q);
}
}
|
Javascript
<script>
function getSum(BITree, index) {
let ans = 0;
index += 1;
while (index > 0) {
ans += BITree[index];
index -= index & (-index);
}
return ans;
}
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);
for (let i = 0; i <= n; i++)
BITree[i] = 0;
for (let i = 0; i < n; i++)
updateBIT(BITree, n, i, arr[i]);
return BITree;
}
function getLowerBound(BITree, arr, n, k) {
let lb = -1;
let l = 0, r = n - 1;
while (l <= r) {
let mid = Math.floor(l + (r - l) / 2);
if (getSum(BITree, mid) >= k) {
r = mid - 1;
lb = mid;
}
else
l = mid + 1;
}
return lb;
}
function performQueries(A, n, q) {
let BITree = constructBITree(A, n);
for (let i = 0;
i < q.length;
i++) {
let id = q[i][0];
if (id == 1) {
let idx = q[i][1];
let val = q[i][2];
A[idx] += val;
updateBIT(BITree, n, idx, val);
}
else {
let k = q[i][1];
let lb = getLowerBound(BITree,
A, n, k);
document.write(lb + "<br>" );
}
}
}
let A = [1, 2, 3, 5, 8];
let n = A.length;
let q = [[1, 0, 2],
[2, 5, 0],
[1, 3, 5]];
performQueries(A, n, q);
</script>
|
Time Complexity: O(Q*(logN)2)
Auxiliary Space: O(N)
Share your thoughts in the comments
Please Login to comment...