Queries for elements having values within the range A to B in the given index range using Segment Tree

Given an array arr[] of N elements and two integers A to B, the task is to answer Q queries each having two integers L and R. For each query, the task is to find the number of elements in the subarray arr[L…R] which lies within the range A to B (both included).
Examples:Â
Input: arr[] = {7, 3, 9, 13, 5, 4}, A=4, B=7Â
query = { 1, 5 }Â
Output: 2Â
Explanation :Â
Only 5 and 4 lies within 4 to 7Â
in the subarray {3, 9, 13, 5, 4}.Input: arr[] = {0, 1, 2, 3, 4, 5, 6, 7}, A=1, B=5Â
query = { 3, 5 }Â
Output: 3Â
Explanation :Â
All the elements 3, 4 and 5 lies within 1 to 5Â
in the subarray {3, 4, 5}.
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 lies within the range A to B.Â
Below is the implementation of the above approach:Â Â
C++14
// C++ implementation of the approach#include <bits/stdc++.h>using namespace std;Â
// Query procedure to get the answer// for each query l and r are query rangeint query(int arr[], int n, int A, int B, int L, int R){Â Â Â Â int count = 0;Â Â Â Â for (int i = L; i <= R; i++) {Â Â Â Â Â Â Â Â if (arr[i] >= A && arr[i] <= B) {Â Â Â Â Â Â Â Â Â Â Â Â count++;Â Â Â Â Â Â Â Â }Â Â Â Â }Â Â Â Â return count;}Â
// Driver codeint main(){Â Â Â Â int arr[] = { 7, 3, 9, 13, 5, 4 };Â Â Â Â int n = sizeof(arr) / sizeof(arr[0]);Â Â Â Â int A = 4, B = 7;Â
    cout << query(arr, n, A, B, 1, 5) << endl;Â
    return 0;} |
Java
import java.util.*;Â
public class GFG {Â
    // Query procedure to get the answer    // for each query l and r are query range    public static int query(int[] arr, int n, int A, int B,                            int L, int R)    {        int count = 0;        for (int i = L; i <= R; i++) {            if (arr[i] >= A && arr[i] <= B) {                count++;            }        }        return count;    }Â
    // Driver code    public static void main(String[] args)    {        int[] arr = { 7, 3, 9, 13, 5, 4 };        int n = arr.length;        int A = 4, B = 7;Â
        System.out.println(query(arr, n, A, B, 1, 5));    }}// This code is contributed by rambabuguphka |
Python3
# Query procedure to get the answer# for each query l and r are query rangedef query(arr, n, A, B, L, R):    count = 0    for i in range(L, R+1):                 # Count 1 if element is in range l and r        if arr[i] >= A and arr[i] <= B:            count += 1         #Return total count    return countÂ
# Test casearr = [7, 3, 9, 13, 5, 4]n = len(arr)A = 4B = 7print(query(arr, n, A, B, 1, 5)) |
Javascript
// Query procedure to get the answer// for each query l and r are query rangefunction query(arr, n, A, B, L, R) {Â
    let count = 0;    for (let i = L; i <= R; i++) {                 // if eleement is in range l and r count 1        if (arr[i] >= A && arr[i] <= B) {            count++;        }    }    // Return total count    return count;}Â
const arr = [7, 3, 9, 13, 5, 4];const n = arr.length;const A = 4, B = 7;console.log(query(arr, n, A, B, 1, 5)); |
Output:
2
Time Complexity: O(n * q)
Space Complexity: O(1)
Efficient approach:Â
Build a Segment Tree.
Representation of Segment treesÂ
1. Leaf Nodes are the elements of the input array.Â
2. Each internal node contains the number of leaves which lies within the range A to B of all leaves under it.
Construction of Segment Tree from given arrayÂ
We start with a segment arr[0 . . . n-1]. and every time we divide the current segment into two halves(if it has not yet become a segment of length 1), and then call the same procedure on both halves, and for each such segment, we store the number of elements which lies within the range A to B of all nodes under it.
Time complexity of this approach will be O(q * log(n))
Below is the implementation of the above approach:Â Â
C++
// C++ implementation of the approach#include <bits/stdc++.h>using namespace std;Â
// Procedure to build the segment treevoid buildTree(vector<int>& tree, int* arr,               int index, int s, int e, int A, int B){Â
    // Reached the leaf node    // of the segment tree    if (s == e) {        if (arr[s] >= A && arr[s] <= B)            tree[index] = 1;        else            tree[index] = 0;        return;    }Â
    // Recursively call the buildTree    // on both the nodes of the tree    int mid = (s + e) / 2;    buildTree(tree, arr, 2 * index, s, mid, A, B);    buildTree(tree, arr, 2 * index + 1, mid + 1, e, A, B);Â
    tree[index] = tree[2 * index] + tree[2 * index + 1];}Â
// Query procedure to get the answer// for each query l and r are query rangeint query(vector<int> tree, int index, int s,          int e, int l, int r){Â
    // 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) {        return tree[index];    }Â
    // 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)            + query(tree, 2 * index + 1, mid + 1, e, l, r));}Â
// Driver codeint main(){Â Â Â Â int arr[] = { 7, 3, 9, 13, 5, 4 };Â Â Â Â int n = sizeof(arr) / sizeof(arr[0]);Â Â Â Â vector<int> tree(4 * n + 1);Â
    int L = 1, R = 5, A = 4, B = 7;Â
    buildTree(tree, arr, 1, 0, n - 1, A, B);Â
    cout << query(tree, 1, 0, n - 1, L, R)         << endl;    return 0;} |
Java
// Java implementation of the approach class GFG{     // Procedure to build the segment tree static void buildTree(int tree[] , int arr[] ,                       int index, int s, int e,                      int A, int B) {          // Reached the leaf node     // of the segment tree     if (s == e)     {         if (arr[s] >= A && arr[s] <= B)             tree[index] = 1;         else            tree[index] = 0;                      return;     } Â
    // Recursively call the buildTree     // on both the nodes of the tree     int mid = (s + e) / 2;     buildTree(tree, arr, 2 * index,               s, mid, A, B);     buildTree(tree, arr, 2 * index + 1,              mid + 1, e, A, B); Â
    tree[index] = tree[2 * index] +                   tree[2 * index + 1]; } Â
// Query procedure to get the answer // for each query l and r are query range static int query(int tree[], int index, int s,                  int e, int l, int r) {          // 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)    {         return tree[index];     } Â
    // 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) +             query(tree, 2 * index + 1,                   mid + 1, e, l, r)); } Â
// Driver code public static void main (String []args){ Â Â Â Â int arr[] = { 7, 3, 9, 13, 5, 4 }; Â Â Â Â int n = arr.length;Â Â Â Â int tree[] = new int [(4 * n + 1)]; Â
    int L = 1, R = 5, A = 4, B = 7; Â
    buildTree(tree, arr, 1, 0, n - 1, A, B); Â
    System.out.print(query(tree, 1, 0, n - 1, L, R));} }Â
// This code is contributed by chitranayal |
Python3
# Python3 implementation of the approachÂ
# Procedure to build the segment treedef buildTree(tree,arr,index, s, e, A, B):Â
    # Reached the leaf node    # of the segment tree    if (s == e):        if (arr[s] >= A and arr[s] <= B):            tree[index] = 1        else:            tree[index] = 0        returnÂ
    # Recursively call the buildTree    # on both the nodes of the tree    mid = (s + e) // 2    buildTree(tree, arr, 2 * index, s, mid, A, B)    buildTree(tree, arr, 2 * index + 1, mid + 1, e, A, B)Â
    tree[index] = tree[2 * index] + tree[2 * index + 1]Â
# Query procedure to get the answer# for each query l and r are query rangedef query(tree, index, s, e, l, r):Â
    # out of bound or no overlap    if (r < s or l > e):        return 0Â
    # Complete overlap    # Query range completely lies in    # the segment tree node range    if (s >= l and e <= r):        return tree[index]Â
    # Partially overlap    # Query range partially lies in    # the segment tree node range    mid = (s + e) // 2    return (query(tree, 2 * index, s, mid, l, r)            + query(tree, 2 * index + 1, mid + 1, e, l, r))Â
# Driver codeif __name__ == '__main__':Â Â Â Â arr=[7, 3, 9, 13, 5, 4]Â Â Â Â n = len(arr)Â Â Â Â tree=[0]*(4 * n + 1)Â
    L = 1    R = 5    A = 4    B = 7Â
    buildTree(tree, arr, 1, 0, n - 1, A, B)Â
    print(query(tree, 1, 0, n - 1, L, R))Â
# This code is contributed by mohit kumar 29 |
C#
// C# implementation of the approach using System;Â
class GFG{     // Procedure to build the segment tree static void buildTree(int[] tree, int[] arr,                       int index, int s, int e,                       int A, int B) {          // Reached the leaf node     // of the segment tree     if (s == e)     {         if (arr[s] >= A && arr[s] <= B)             tree[index] = 1;         else            tree[index] = 0;                      return;     } Â
    // Recursively call the buildTree     // on both the nodes of the tree     int mid = (s + e) / 2;     buildTree(tree, arr, 2 * index,               s, mid, A, B);     buildTree(tree, arr, 2 * index + 1,               mid + 1, e, A, B); Â
    tree[index] = tree[2 * index] +                   tree[2 * index + 1]; } Â
// Query procedure to get the answer // for each query l and r are query range static int query(int[] tree, int index, int s,                  int e, int l, int r) {          // 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)     {         return tree[index];     } Â
    // 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) +             query(tree, 2 * index + 1,                   mid + 1, e, l, r)); } Â
// Driver code public static void Main () { Â Â Â Â int[] arr = new int[] { 7, 3, 9, 13, 5, 4 }; Â Â Â Â int n = arr.Length; Â Â Â Â int[] tree = new int [(4 * n + 1)]; Â
    int L = 1, R = 5, A = 4, B = 7; Â
    buildTree(tree, arr, 1, 0, n - 1, A, B); Â
    Console.Write(query(tree, 1, 0, n - 1, L, R)); } } Â
// This code is contributed by sanjoy_62 |
Javascript
<script>Â
// Javascript implementation of the approach Â
// Procedure to build the segment tree function buildTree(tree, arr, index, s, e, A, B){         // Reached the leaf node     // of the segment tree     if (s == e)     {         if (arr[s] >= A && arr[s] <= B)             tree[index] = 1;         else            tree[index] = 0;                        return;     }        // Recursively call the buildTree     // on both the nodes of the tree     let mid = Math.floor((s + e) / 2);     buildTree(tree, arr, 2 * index,               s, mid, A, B);     buildTree(tree, arr, 2 * index + 1,              mid + 1, e, A, B);        tree[index] = tree[2 * index] +                   tree[2 * index + 1]; }Â
// Query procedure to get the answer // for each query l and r are query range function query(tree, index, s, e, l, r){         // 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)    {         return tree[index];     }        // Partially overlap     // Query range partially lies in     // the segment tree node range     let mid = Math.floor((s + e) / 2);     return (query(tree, 2 * index,                   s, mid, l, r) +             query(tree, 2 * index + 1,                   mid + 1, e, l, r)); }Â
// Driver code let arr = [ 7, 3, 9, 13, 5, 4 ];let n = arr.length;let tree = new Array(4 * n + 1); let L = 1, R = 5, A = 4, B = 7; buildTree(tree, arr, 1, 0, n - 1, A, B); Â
document.write(query(tree, 1, 0, n - 1, L, R));Â
// This code is contributed by avanitrachhadiya2155Â
</script> |
2
The space complexity of the implementation is O(n) because the segment tree vector has a size of 4n+1, which is the maximum size of a full binary tree with n leaves. In addition, the buildTree and query functions use a constant amount of extra space for their local variables and parameters, which does not depend on the size of the input array. Therefore, the overall space complexity of the implementation is O(n).
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 zambiatek!



