Skip to content
Related Articles

Related Articles

Queries to find the minimum index in a range [L, R] having at least value X with updates
  • Difficulty Level : Expert
  • Last Updated : 28 Jan, 2021

Given an array arr[] consisting of N integers and an array Queries[] consisting of Q queries of the type {X, L, R} to perform following operations:

  • If the value of X is 1, then update the array element at Xth index to L.
  • Otherwise, find the minimum index j in the range [L, R] such that arr[j] ≥ X. If no such j exists, then print “-1”.

Examples:

Input: arr[] = {1, 3, 2, 4, 6}, Queries[][] = {{2, 0, 4}, {1, 2, 5}, {4, 0, 4}, {0, 0, 4}}
Output: 1 2 0
Explanation:  
Query 1: find(2, 0, 4) => First element which is at least 2 is 3. So, its index is 1.
Query 2: update(2, 5) => arr[] = {1, 3, 5, 4, 6}.
Query 3: find(4, 0, 4) => First element which is at least 4 is 5. So, its index is 2.
Query 4: find(0, 0, 4) => First element which is at least 0 is 1. So, its index is 0.

Input: arr[] = {1}, Queries[][] = {{2, 0, 0}};
Output: 1 2 0
Explanation:
Query 1: find(2, 0, 0) => No element is greater than 2. Therefore, print -1.

Naive Approach: The simplest approach is to traverse the array for each query. For the queries of Type 1, update A[X] to L. For the query of Type 2, traverse the array arr[] over the range [L, R] and find the minimum index j satisfying the condition. If no such index is found, then print “-1”
Time Complexity: O(N*Q)
Auxiliary Space: O(N)

Efficient Approach: To optimize the above approach, the idea is to use Segment Tree in order to perform queries efficiently. Follow the steps below to solve the problem:



  • Construct a Segment Tree where each node will represent the maximum value in the range of that node. For example, for any given range [i, j], its corresponding node will contain the maximum value in that range.
  • Initialize a variable, say ans.
  • Now, for queries of type 2, if the current range does not lie inside the range [L, R], then traverse its left subtree.
  • Now, in the left subtree, if the maximum exceeds X and the current range lies inside the range [L, R], then go to the mid-point of that range and check if its value is greater than X or not. If found to be true, visit its left part. Otherwise, visit its right part.
  • Update the variable ans as the minimum index between the given range if it exists.
  • Continue the above steps, until the left part of the range becomes equal to the right part.
  • After completing the above steps, print the value of ans as the result.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include <bits/stdc++.h>
#define maxN 100
using namespace std;
 
// Stores nodes value of the Tree
int Tree[4 * maxN];
 
// Function to build segment tree
void build(int arr[], int index,
           int s, int e)
{
    // Base Case
    if (s == e)
        Tree[index] = arr[s];
 
    else {
        // Find the value of mid
        int m = (s + e) / 2;
 
        // Update for left subtree
        build(arr, 2 * index, s, m);
 
        // Update for right subtree
        build(arr, 2 * index + 1,
              m + 1, e);
 
        // Update the value at the
        // current index
        Tree[index]
            = max(Tree[2 * index],
                  Tree[2 * index + 1]);
    }
}
 
// Function for finding the index
// of the first element at least x
int atleast_x(int index, int s, int e,
              int ql, int qr, int x)
{
    // If current range does
    // not lie in query range
    if (ql > e || qr < s)
        return -1;
 
    // If current range is inside
    // of query range
    if (s <= ql && e <= qr) {
 
        // Maximum value in this
        // range is less than x
        if (Tree[index] < x)
            return -1;
 
        // Finding index of first
        // value in this range
        while (s != e) {
            int m = (s + e) / 2;
 
            // Update the value of
            // the minimum index
            if (Tree[2 * index] >= x) {
                e = m;
                index = 2 * index;
            }
            else {
                s = m + 1;
                index = 2 * index + 1;
            }
        }
        return s;
    }
 
    // Find mid of the current range
    int m = (s + e) / 2;
 
    // Left subtree
    int val = atleast_x(2 * index, s,
                        m, ql, qr, x);
 
    if (val != -1)
        return val;
 
    // If it does not lie in
    // left subtree
    return atleast_x(2 * index + 1, m + 1,
                     e, ql, qr, x);
}
 
// Function for updating segment tree
void update(int index, int s, int e,
            int new_val, int pos)
{
    // Update the value, we
    // reached leaf node
    if (s == e)
        Tree[index] = new_val;
 
    else {
 
        // Find the mid
        int m = (s + e) / 2;
 
        if (pos <= m) {
 
            // If pos lies in the
            // left subtree
            update(2 * index, s, m,
                   new_val, pos);
        }
        else {
 
            // pos lies in the
            // right subtree
            update(2 * index + 1,
                   m + 1, e,
                   new_val, pos);
        }
 
        // Update the maximum value
        // in the range
        Tree[index]
            = max(Tree[2 * index],
                  Tree[2 * index + 1]);
    }
}
 
// Function to print the answer
// for the given queries
void printAnswer(int* arr, int n)
{
    // Build segment tree
    build(arr, 1, 0, n - 1);
 
    // Find index of first value
    // atleast 2 in range [0, n-1]
    cout << atleast_x(1, 0, n - 1,
                      0, n - 1, 2)
         << "\n";
 
    // Update value at index 2 to 5
    arr[2] = 5;
    update(1, 0, n - 1, 5, 2);
 
    // Find index of first value
    // atleast 4 in range [0, n-1]
    cout << atleast_x(1, 0, n - 1,
                      0, n - 1, 4)
         << "\n";
 
    // Find index of first value
    // atleast 0 in range [0, n-1]
    cout << atleast_x(1, 0, n - 1,
                      0, n - 1, 0)
         << "\n";
}
 
// Driver Code
int main()
{
    int arr[] = { 1, 3, 2, 4, 6 };
    int N = sizeof(arr) / sizeof(arr[0]);
 
    // Function Call
    printAnswer(arr, N);
 
    return 0;
}

Java




// Java program to implement
// the above approach
import java.util.*;
 
class GFG
{
  
static int maxN = 100;
 
// Stores nodes value of the Tree
static int Tree[] = new int[4 * maxN];
 
// Function to build segment tree
static void build(int arr[], int index,
           int s, int e)
{
    // Base Case
    if (s == e)
        Tree[index] = arr[s];
 
    else
    {
       
        // Find the value of mid
        int m = (s + e) / 2;
 
        // Update for left subtree
        build(arr, 2 * index, s, m);
 
        // Update for right subtree
        build(arr, 2 * index + 1,
              m + 1, e);
 
        // Update the value at the
        // current index
        Tree[index]
            = Math.max(Tree[2 * index],
                  Tree[2 * index + 1]);
    }
}
 
// Function for finding the index
// of the first element at least x
static int atleast_x(int index, int s, int e,
              int ql, int qr, int x)
{
    // If current range does
    // not lie in query range
    if (ql > e || qr < s)
        return -1;
 
    // If current range is inside
    // of query range
    if (s <= ql && e <= qr) {
 
        // Maximum value in this
        // range is less than x
        if (Tree[index] < x)
            return -1;
 
        // Finding index of first
        // value in this range
        while (s != e) {
            int m = (s + e) / 2;
 
            // Update the value of
            // the minimum index
            if (Tree[2 * index] >= x) {
                e = m;
                index = 2 * index;
            }
            else {
                s = m + 1;
                index = 2 * index + 1;
            }
        }
        return s;
    }
 
    // Find mid of the current range
    int m = (s + e) / 2;
 
    // Left subtree
    int val = atleast_x(2 * index, s,
                        m, ql, qr, x);
    if (val != -1)
        return val;
 
    // If it does not lie in
    // left subtree
    return atleast_x(2 * index + 1, m + 1,
                     e, ql, qr, x);
}
 
// Function for updating segment tree
static void update(int index, int s, int e,
            int new_val, int pos)
{
   
    // Update the value, we
    // reached leaf node
    if (s == e)
        Tree[index] = new_val;
    else
    {
 
        // Find the mid
        int m = (s + e) / 2;
 
        if (pos <= m)
        {
 
            // If pos lies in the
            // left subtree
            update(2 * index, s, m,
                   new_val, pos);
        }
        else
        {
 
            // pos lies in the
            // right subtree
            update(2 * index + 1,
                   m + 1, e,
                   new_val, pos);
        }
 
        // Update the maximum value
        // in the range
        Tree[index]
            = Math.max(Tree[2 * index],
                  Tree[2 * index + 1]);
    }
}
 
// Function to print the answer
// for the given queries
static void printAnswer(int[] arr, int n)
{
   
    // Build segment tree
    build(arr, 1, 0, n - 1);
 
    // Find index of first value
    // atleast 2 in range [0, n-1]
    System.out.println(atleast_x(1, 0, n - 1,
                      0, n - 1, 2));
 
    // Update value at index 2 to 5
    arr[2] = 5;
    update(1, 0, n - 1, 5, 2);
 
    // Find index of first value
    // atleast 4 in range [0, n-1]
    System.out.println(atleast_x(1, 0, n - 1,
                      0, n - 1, 4));
 
    // Find index of first value
    // atleast 0 in range [0, n-1]
    System.out.println(atleast_x(1, 0, n - 1,
                      0, n - 1, 0));
}
    
// Driver code
public static void main(String[] args)
{
    int arr[] = { 1, 3, 2, 4, 6 };
    int N = arr.length;
 
    // Function Call
    printAnswer(arr, N);
}
}
 
// This code is contributed by susmitakundugoaldanga.

Python3




# Python 3 program for the above approach
maxN = 100
 
# Stores nodes value of the Tree
Tree = [0 for i in range(4 * maxN)]
 
# Function to build segment tree
def build(arr, index, s, e):
   
    # Base Case
    global Tree
    global max
    if (s == e):
        Tree[index] = arr[s]
    else:
       
        # Find the value of mid
        m = (s + e) // 2
 
        # Update for left subtree
        build(arr, 2 * index, s, m)
 
        # Update for right subtree
        build(arr, 2 * index + 1, m + 1, e)
 
        # Update the value at the
        # current index
        Tree[index] = max(Tree[2 * index],
                          Tree[2 * index + 1])
 
# Function for finding the index
# of the first element at least x
def atleast_x(index, s,  e,  ql, qr, x):
    global Tree
    global max
     
    # If current range does
    # not lie in query range
    if (ql > e or qr < s):
        return -1
 
    # If current range is inside
    # of query range
    if (s <= ql and e <= qr):
       
        # Maximum value in this
        # range is less than x
        if (Tree[index] < x):
            return -1;
 
        # Finding index of first
        # value in this range
        while (s != e):
            m = (s + e) // 2
 
            # Update the value of
            # the minimum index
            if (Tree[2 * index] >= x):
                e = m
                index = 2 * index
            else:
                s = m + 1
                index = 2 * index + 1
        return s
 
    # Find mid of the current range
    m = (s + e) // 2
 
    # Left subtree
    val = atleast_x(2 * index, s, m, ql, qr, x)
    if (val != -1):
        return val
 
    # If it does not lie in
    # left subtree
    return atleast_x(2 * index + 1, m + 1,e, ql, qr, x)
 
# Function for updating segment tree
def update(index, s, e, new_val, pos):
    global Tree
    global max
     
    # Update the value, we
    # reached leaf node
    if (s == e):
        Tree[index] = new_val
    else:
 
        # Find the mid
        m = (s + e) // 2
 
        if (pos <= m):
            # If pos lies in the
            # left subtree
            update(2 * index, s, m,new_val, pos)
        else:
            # pos lies in the
            # right subtree
            update(2 * index + 1, m + 1, e, new_val, pos)
 
        # Update the maximum value
        # in the range
        Tree[index] = max(Tree[2 * index], Tree[2 * index + 1])
 
# Function to print the answer
# for the given queries
def printAnswer(arr, n):
    global Tree
    global max
     
    # Build segment tree
    build(arr, 1, 0, n - 1)
 
    # Find index of first value
    # atleast 2 in range [0, n-1]
    print(atleast_x(1, 0, n - 1, 0, n - 1, 2))
 
    # Update value at index 2 to 5
    arr[2] = 5
    update(1, 0, n - 1, 5, 2)
 
    # Find index of first value
    # atleast 4 in range [0, n-1]
    print(atleast_x(1, 0, n - 1, 0, n - 1, 4))
 
    # Find index of first value
    # atleast 0 in range [0, n-1]
    print(atleast_x(1, 0, n - 1, 0, n - 1, 0))
 
# Driver Code
if __name__ == '__main__':
    arr =  [1, 3, 2, 4, 6]
    N =  len(arr)
     
    # Function Call
    printAnswer(arr, N)
 
    # This code is contributed by bgangwar59.

C#




// C# program to implement
// the above approach
using System;
class GFG
{
   
static int maxN = 100;
 
// Stores nodes value of the Tree
static int[] Tree = new int[4 * maxN];
 
// Function to build segment tree
static void build(int[] arr, int index,
           int s, int e)
{
    // Base Case
    if (s == e)
        Tree[index] = arr[s];
 
    else
    {
       
        // Find the value of mid
        int m = (s + e) / 2;
 
        // Update for left subtree
        build(arr, 2 * index, s, m);
 
        // Update for right subtree
        build(arr, 2 * index + 1,
              m + 1, e);
 
        // Update the value at the
        // current index
        Tree[index]
            = Math.Max(Tree[2 * index],
                  Tree[2 * index + 1]);
    }
}
 
// Function for finding the index
// of the first element at least x
static int atleast_x(int index, int s, int e,
              int ql, int qr, int x)
{
    // If current range does
    // not lie in query range
    if (ql > e || qr < s)
        return -1;
 
    // If current range is inside
    // of query range
    if (s <= ql && e <= qr) {
 
        // Maximum value in this
        // range is less than x
        if (Tree[index] < x)
            return -1;
     
        // Finding index of first
        // value in this range
        while (s != e) {
            int m = (s + e) / 2;
 
            // Update the value of
            // the minimum index
            if (Tree[2 * index] >= x) {
                e = m;
                index = 2 * index;
            }
            else {
                s = m + 1;
                index = 2 * index + 1;
            }
        }
        return s;
    }
 
    // Find mid of the current range
    int mm = (s + e) / 2;
 
    // Left subtree
    int val = atleast_x(2 * index, s,
                        mm, ql, qr, x);
    if (val != -1)
        return val;
 
    // If it does not lie in
    // left subtree
    return atleast_x(2 * index + 1, mm + 1,
                     e, ql, qr, x);
}
 
// Function for updating segment tree
static void update(int index, int s, int e,
            int new_val, int pos)
{
   
    // Update the value, we
    // reached leaf node
    if (s == e)
        Tree[index] = new_val;
    else
    {
 
        // Find the mid
        int m = (s + e) / 2;
 
        if (pos <= m)
        {
 
            // If pos lies in the
            // left subtree
            update(2 * index, s, m,
                   new_val, pos);
        }
        else
        {
 
            // pos lies in the
            // right subtree
            update(2 * index + 1,
                   m + 1, e,
                   new_val, pos);
        }
 
        // Update the maximum value
        // in the range
        Tree[index]
            = Math.Max(Tree[2 * index],
                  Tree[2 * index + 1]);
    }
}
 
// Function to print the answer
// for the given queries
static void printAnswer(int[] arr, int n)
{
   
    // Build segment tree
    build(arr, 1, 0, n - 1);
 
    // Find index of first value
    // atleast 2 in range [0, n-1]
    Console.WriteLine(atleast_x(1, 0, n - 1,
                      0, n - 1, 2));
 
    // Update value at index 2 to 5
    arr[2] = 5;
    update(1, 0, n - 1, 5, 2);
 
    // Find index of first value
    // atleast 4 in range [0, n-1]
    Console.WriteLine(atleast_x(1, 0, n - 1,
                      0, n - 1, 4));
 
    // Find index of first value
    // atleast 0 in range [0, n-1]
    Console.WriteLine(atleast_x(1, 0, n - 1,
                      0, n - 1, 0));
}
 
// Driver code
static void Main()
{
    int[] arr = { 1, 3, 2, 4, 6 };
    int N = arr.Length;
 
    // Function Call
    printAnswer(arr, N);
 
}
}
 
// This code is contributed by sanjoy_62
Output: 
1
2
0

 

Time Complexity: O(Q*log N)
Auxiliary Space: O(N)

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with industry experts, please refer Geeks Classes Live and Geeks Classes Live USA

My Personal Notes arrow_drop_up
Recommended Articles
Page :