Queries for elements greater than K in the given index range using Segment Tree

Given an array arr[] of N elements and a number of queries where each query will contain three integers L, R and K. For each query, the task is to find the number of elements in the subarray arr[L…R] which are greater than K.

Examples:

Input: arr[] = {7, 3, 9, 13, 5, 4}, q[] = {{0, 3, 6}, {1, 5, 8}}
Output:
3
2
Query 1: Only 7, 9 and 13 are greater
than 6 in the subarray {7, 3, 9, 13}.
Query 2: Only 9 and 13 are greater
than 8 in the subarray {3, 9, 13, 5, 4}.



Input: arr[] = {0, 1, 2, 3, 4, 5, 6, 7}, q[] = {{0, 7, 3}, {4, 6, 10}}
Output:
4
0

Prerequisite: Segment tree

Naive approach: Find the answer for each query by simply traversing the array from index l till r and keep adding 1 to the count whenever the array element is greater than k. Time Complexity of this approach will be O(n * q).

Efficient approach: Build a Segment Tree with a vector at each node containing all the elements of the sub-range in a sorted order. Answer each query using the segment tree where Binary Search can be used to calculate how many numbers are present in each node whose sub-range lies within the query range which is greater than K. Time complexity of this approach will be O(q * log(n) * log(n))

Below is the implementation of the above approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
  
// Merge procedure to merge two
// vectors into a single vector
vector<int> merge(vector<int>& v1, vector<int>& v2)
{
    int i = 0, j = 0;
  
    // Final vector to return
    // after merging
    vector<int> v;
  
    // Loop continues until it reaches
    // the end of one of the vectors
    while (i < v1.size() && j < v2.size()) {
        if (v1[i] <= v2[j]) {
            v.push_back(v1[i]);
            i++;
        }
        else {
            v.push_back(v2[j]);
            j++;
        }
    }
  
    // Here, simply add the remaining
    // elements to the vector v
    for (int k = i; k < v1.size(); k++)
        v.push_back(v1[k]);
    for (int k = j; k < v2.size(); k++)
        v.push_back(v2[k]);
    return v;
}
  
// Procedure to build the segment tree
void buildTree(vector<int>* tree, int* arr,
               int index, int s, int e)
{
  
    // Reached the leaf node
    // of the segment tree
    if (s == e) {
        tree[index].push_back(arr[s]);
        return;
    }
  
    // Recursively call the buildTree
    // on both the nodes of the tree
    int mid = (s + e) / 2;
    buildTree(tree, arr, 2 * index, s, mid);
    buildTree(tree, arr, 2 * index + 1, mid + 1, e);
  
    // Storing the final vector after merging
    // the two of its sorted child vector
    tree[index] = merge(tree[2 * index], tree[2 * index + 1]);
}
  
// Query procedure to get the answer
// for each query l and r are query range
int query(vector<int>* tree, int index, int s,
          int e, int l, int r, int k)
{
  
    // out of bound or no overlap
    if (r < s || l > e)
        return 0;
  
    // Complete overlap
    // Query range completely lies in
    // the segment tree node range
    if (s >= l && e <= r) {
        // binary search to find index of k
        return (tree[index].size()
                - (lower_bound(tree[index].begin(),
                               tree[index].end(), k)
                   - tree[index].begin()));
    }
  
    // Partially overlap
    // Query range partially lies in
    // the segment tree node range
    int mid = (s + e) / 2;
    return (query(tree, 2 * index, s,
                  mid, l, r, k)
            + query(tree, 2 * index + 1, mid + 1,
                    e, l, r, k));
}
  
// Function to perform the queries
void performQueries(int L[], int R[], int K[],
                    int n, int q, vector<int> tree[])
{
    for (int i = 0; i < q; i++) {
        cout << query(tree, 1, 0, n - 1,
                      L[i] - 1, R[i] - 1, K[i])
             << endl;
    }
}
  
// Driver code
int main()
{
    int arr[] = { 7, 3, 9, 13, 5, 4 };
    int n = sizeof(arr) / sizeof(arr[0]);
    vector<int> tree[4 * n + 1];
    buildTree(tree, arr, 1, 0, n - 1);
  
    // 1-based indexing
    int L[] = { 1, 2 };
    int R[] = { 4, 6 };
    int K[] = { 6, 8 };
  
    // Number of queries
    int q = sizeof(L) / sizeof(L[0]);
  
    performQueries(L, R, K, n, q, tree);
  
    return 0;
}

chevron_right


Output:

3
2


My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.