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++

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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.

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# 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.

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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

chevron_right


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.

My Personal Notes arrow_drop_up
Recommended Articles
Page :