Queries to find the Lower Bound of K from Prefix Sum Array with updates using Fenwick Tree


A foremost series summation array is an assemblage that accumulates the sum of interlacing elements up to an express index. It is a widely utilized tactic in the reconfiguration of assemblages to refine time complexity. Fenwick Tree, also recognized as Binary Indexed Tree (BIT), is a form of database that proficiently modernizes components and computes a preceding series summation in logarithmic time complexity.

Within this article, we shall confer on how to disclose the lesser extreme boundary of a given value, referred to as K, from a series summation array with modernizations utilizing Fenwick Tree in C++.

Syntax

The syntax defines two functions, update and query, and a main function for a Fenwick Tree, which is a data structure used for efficient range query and update operations. The update function takes in an index idx, a value val, the size of the array n, and the Fenwick Tree array BIT. It updates the Fenwick Tree by adding val to the node at index idx and all of its ancestors. The query function takes in an index idx and the Fenwick Tree array BIT. It returns the cumulative sum of all the nodes from the root node to the node at index idx. The main function declares the size of the array n, the prefix sum array arr, and the Fenwick Tree array BIT, which is initialized to 0.

void update(int idx, int val, int n, int BIT[]) {
   while (idx <= n) {
      BIT[idx] += val;
      idx += (idx & -idx);
   }
}
int query(int idx, int BIT[]) {
   int sum = 0;
   while (idx > 0) {
      sum += BIT[idx];
      idx -= (idx & -idx);
   }
   return sum;
}
// Driver code
int main() {
   int n; 
   int arr[n+1];
   int BIT[n+1] = {0}; 
   return 0;
}

Algorithm

To ascertain the minimum value of K in a prefix sum array with Fenwick Tree updates, follow these intricate steps −

  • Instantiate a Fenwick Tree (BIT) with a size of n+1, initializing all elements to 0.

  • Employ the update() function to modify the Fenwick Tree with the given prefix sum array.

  • Execute queries on the Fenwick Tree to determine the lower bound of K. Commence with the most significant bit in the binary representation of n, and iterate from this bit to the least significant bit. Verify if the current prefix sum is less than or equal to K using the query() function. If it satisfies this condition, subtract the current prefix sum from K and update the index to move to the next bit. If it doesn't, move to the next bit without updating the index.

  • After traversing all the bits, the index will denote the lower bound of K in the prefix sum array.

  • Output the obtained index as the lower bound of K.

Approaches

  • Approach 1 − Binary Search on Fenwick Tree. In this approach, we perform binary search on the Fenwick Tree to find the lower bound of K.

  • Approach 2 − Binary Search on Fenwick Tree with Lazy Propagation.

Approach 1

To tackle this problem, we commence by setting the left and right pointers to 1 and n (representing the size of the prefix sum array) respectively. and employ a binary search strategy to identify the index i that corresponds to the largest prefix sum that is either less than or equal to K. We then update the position of the left or right pointer, depending on whether the value of prefix_sum[i] is less than or equal to K or not.

Example

The underlying mechanism of this code is the utilization of a Fenwick Tree, also referred to as a Binary Indexed Tree. Its purpose is to determine the lower bound of a designated value, denoted as 'k', within a prefix sum array. This is accomplished through the construction of the Fenwick Tree using the update function, which incorporates the values of each element in the prefix sum array into its corresponding position within the Fenwick Tree.

The findLowerBound function then employs a binary search algorithm to pinpoint the lower bound of 'k' in the prefix sum array through the employment of the query function. This function computes the cumulative sum of values up to the current index in the Fenwick Tree. Ultimately, the code culminates in the identification of the index of the lower bound of 'k' within the prefix sum array and displays the result to the console.

#include <iostream>
using namespace std;
void update(int i, int v, int n, int b[]) {
    while (i <= n) {
        b[i] += v;
        i += (i & -i);
    }
}
int query(int i, int b[]) {
    int s = 0;
    while (i > 0) {
        s += b[i];
        i -= (i & -i);
    }
    return s;
}
int findLowerBound(int k, int n, int p[], int b[]) {
    int l = 1, r = n, idx = 0;
    while (l <= r) {
        int m = (l + r) / 2;
        int msum = query(m, b);
        if (msum <= k) {
            idx = m;
            l = m + 1;
        } else {
            r = m - 1;
        }
    }
    return idx;
}
int main() {
    int n = 5;
    int p[] = {0, 1, 3, 6, 10, 15};
    int b[n + 1] = {0};
    for (int i = 1; i <= n; i++) {
        update(i, p[i], n, b);
    }
    int k = 10, idx;
    idx = findLowerBound(k, n, p, b);
    cout << "The lower bound of " << k << " is at index " << idx << " in the prefix sum array." << endl;
    return 0;
}

Output

The lower bound of 10 is at index 3 in the prefix sum array.

Approach 2

In order to further optimize the Fenwick Tree, a technique known as lazy propagation can be employed. This approach entails deferring updates to the Fenwick Tree until they are actually required, thereby reducing the number of updates and enhancing the efficiency of the query process.

Example

The code presents a solution to locate the lower limit of a given value, K, in a prefix sum array. The prefix sum array is an array in which each element constitutes the aggregate of the elements in the original array up to and including that index. The lower limit is the first index in the prefix sum array where the sum of the elements up to that index is equal to or exceeds K. The solution employs the Fenwick Tree data structure and the lazy propagation technique to augment the efficiency of the solution. The code encompasses functions to modify the Fenwick Tree, calculate the prefix sum, and find the lower limit. The code also initiates the prefix sum array, the Fenwick Tree, and the lazy propagation array. Finally, it outputs the lower limit of K in the prefix sum array.

#include  <iostream>
#include  <cstring>
using namespace std;

void update(int idx, int val, int n, int ft[], int lz[]) {
   while (idx  <= n) ft[idx] += val, idx += (idx & -idx);
}

int getPrefixSum(int idx, int ft[]) {
   int sum = 0;
   while (idx > 0) sum += ft[idx], idx -= (idx & -idx);
   return sum;
}

int findLowerBound(int K, int n, int ps[], int ft[], int lz[]) {
   int l = 1, r = n, lb = 0;
   while (l  <= r) {
      int m = (l + r) / 2, s = getPrefixSum(m, ft) + lz[m];
      if (s  <= K) lb = m, l = m + 1;
      else r = m - 1;
   }
   return lb;
}

int main() {
   int n = 5;
   int ps[] = {0, 1, 3, 6, 10, 15};
   int ft[n + 1], lz[n + 1]; memset(ft, 0, sizeof(ft)); memset(lz, 0, sizeof(lz));
   for (int i = 1; i  <= n; i++) update(i, ps[i] - ps[i - 1], n, ft, lz);
   int K = 10;
   int lb = findLowerBound(K, n, ps, ft, lz);
   cout << "For the given array with size " << n << " and prefix sum array [";
   for (int i = 1; i <= n; i++) {
      cout << ps[i];
      if (i < n) cout << ", ";
   }
   cout << "], the lower bound of " << K << " is at index " << lb << " in the prefix sum array." << endl;
   return 0;
}

Output

For the given array with size 5 and prefix sum array [1, 3, 6, 10, 15], the lower bound of 10 is at index 4 in the prefix sum array.

Conclusion

A discourse on unearthing the elusive threshold of the value K from a meticulously crafted array of prefix sums, fortified with updates, utilizing the ingenious Fenwick Tree algorithm in the realm of C++ programming. Delving into the intricacies of two highly efficient approaches: Binary Search on Fenwick Tree and Binary Search on Fenwick Tree with Lazy Propagation. Carefully selecting the most apt approach based on the specific requirements and constraints of your particular conundrum. May this elucidate the conceptualization and implementation of the elusive quest to find the lower bound of K from a prefix sum array with updates, utilizing the unparalleled power of Fenwick Tree in the realm of C++.

Updated on: 21-Jul-2023

77 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements