Open In App

Queries to find maximum product pair in range with updates

Last Updated : 23 Apr, 2025
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

You are given an array arr[] of positive integers. Your task is to process q queries, each consisting of three integers, of the following two types:

  1. [1, L, R]: Find the maximum product of any two distinct elements in the subarray arr[L…R] (inclusive).
  2. [2, i, val]: Update the element at index i to val (i.e., set arr[i] = val) where val > 0

Examples:

Input: n = 5, q = 3
arr[] = [1, 3, 4, 2, 5]
queries[][] = [ [1, 0, 2], [2, 1, 6], [1, 0, 2] ]
Output: 12 24
Explanation: For the query 1, the maximum product in a range [0, 2] is 3 * 4 = 12. 
For the query 2, after an update, the array becomes [1, 6, 4, 2, 5] 
For the query 3, the maximum product in a range [0, 2] is 6 * 4 = 24. 

[Naive Approach] - O(n * n * q) Time and O(1) Space

The idea is to examine every possible pair of elements in the range [L, R], compute the product for each pair, and keep track of the maximum product found. By brute‑forcing all combinations, we guarantee that the highest possible product pair is identified.

Follow the below given steps:

  • Initialize a variable maxProduct to a very small value and prepare variables to hold the indices or values of the best pair.
  • Iterate an outer loop variable i from L to R.
  • Within that, iterate an inner loop variable j from i + 1 to R.
  • Compute currentProduct = arr[i] * arr[j].
  • If currentProduct exceeds maxProduct, update maxProduct and record the corresponding pair (arr[i], arr[j]).
  • Continue until all pairs have been evaluated.
  • Return or print the pair that produced maxProduct.

Below is given the implementation:

C++
#include <bits/stdc++.h>
using namespace std;

vector<int> solveQueries(vector<int> &arr, 
                vector<vector<int>> &queries) {
    int n = arr.size();

    // to store the result of query of type 1
    vector<int> res;

    // process all the queries
    for(auto query: queries) {

        // to find the maximum 
        // product in the range [L, R]
        if(query[0] == 1) {
            int l = query[1];
            int r = query[2];
            int maxProd = 0;

            // find all possible paris
            for(int i = l; i < r; i++) {
                for(int j = i + 1; j <= r; j++) {
                    maxProd = max(maxProd, arr[i] * arr[j]);
                }
            }

            res.push_back(maxProd);
        }

        // else update the value of arr[i]
        else if(query[0] == 2) {
            int i = query[1];
            int x = query[2];
            arr[i] = x;
        }
    }

    return res;
}

int main() {
    vector<int> arr = {1, 3, 4, 2, 5};
    vector<vector<int>> queries = 
    { {1, 0, 2}, {2, 1, 6}, {1, 0, 2}};
    vector<int> res = solveQueries(arr, queries);
    for(auto i:res) {
        cout << i << " ";
    }
    return 0;
}
Java
import java.util.*;

class GfG {

    public static ArrayList<Integer> solveQueries(
        ArrayList<Integer> arr, ArrayList<ArrayList<Integer>> queries) {
        int n = arr.size();

        // to store the result of query of type 1
        ArrayList<Integer> res = new ArrayList<>();

        // process all the queries
        for (ArrayList<Integer> query : queries) {

            // to find the maximum 
            // product in the range [L, R]
            if (query.get(0) == 1) {
                int l = query.get(1);
                int r = query.get(2);
                int maxProd = 0;

                // find all possible paris
                for (int i = l; i < r; i++) {
                    for (int j = i + 1; j <= r; j++) {
                        maxProd = Math.max(maxProd, arr.get(i) * arr.get(j));
                    }
                }

                res.add(maxProd);
            }

            // else update the value of arr[i]
            else if (query.get(0) == 2) {
                int i = query.get(1);
                int x = query.get(2);
                arr.set(i, x);
            }
        }

        return res;
    }

    public static void main(String[] args) {
        ArrayList<Integer> arr = new ArrayList<>(Arrays.asList(1, 3, 4, 2, 5));
        ArrayList<ArrayList<Integer>> queries = new ArrayList<>();
        queries.add(new ArrayList<>(Arrays.asList(1, 0, 2)));
        queries.add(new ArrayList<>(Arrays.asList(2, 1, 6)));
        queries.add(new ArrayList<>(Arrays.asList(1, 0, 2)));
        ArrayList<Integer> res = solveQueries(arr, queries);
        for (int i : res) {
            System.out.print(i + " ");
        }
    }
}
Python
def solveQueries(arr, queries):
    n = len(arr)

    # to store the result of query of type 1
    res = []

    # process all the queries
    for query in queries:

        # to find the maximum 
        # product in the range [L, R]
        if query[0] == 1:
            l = query[1]
            r = query[2]
            maxProd = 0

            # find all possible paris
            for i in range(l, r):
                for j in range(i + 1, r + 1):
                    maxProd = max(maxProd, arr[i] * arr[j])

            res.append(maxProd)

        # else update the value of arr[i]
        elif query[0] == 2:
            i = query[1]
            x = query[2]
            arr[i] = x

    return res

arr = [1, 3, 4, 2, 5]
queries = [[1, 0, 2], [2, 1, 6], [1, 0, 2]]
res = solveQueries(arr, queries)
for i in res:
    print(i, end=" ")
C#
using System;
using System.Collections.Generic;

class GfG {

    public static List<int> solveQueries(List<int> arr, 
    List<List<int>> queries) {
        int n = arr.Count;

        // to store the result of query of type 1
        List<int> res = new List<int>();

        // process all the queries
        foreach (var query in queries) {

            // to find the maximum 
            // product in the range [L, R]
            if (query[0] == 1) {
                int l = query[1];
                int r = query[2];
                int maxProd = 0;

                // find all possible paris
                for (int i = l; i < r; i++) {
                    for (int j = i + 1; j <= r; j++) {
                        maxProd = Math.Max(maxProd, arr[i] * arr[j]);
                    }
                }

                res.Add(maxProd);
            }

            // else update the value of arr[i]
            else if (query[0] == 2) {
                int i = query[1];
                int x = query[2];
                arr[i] = x;
            }
        }

        return res;
    }

    public static void Main() {
        List<int> arr = new List<int> {1, 3, 4, 2, 5};
        List<List<int>> queries = new List<List<int>> {
            new List<int> {1, 0, 2},
            new List<int> {2, 1, 6},
            new List<int> {1, 0, 2}
        };
        List<int> res = solveQueries(arr, queries);
        foreach (int i in res) {
            Console.Write(i + " ");
        }
    }
}
JavaScript
function solveQueries(arr, queries) {
    let n = arr.length;

    // to store the result of query of type 1
    let res = [];

    // process all the queries
    for (let query of queries) {

        // to find the maximum 
        // product in the range [L, R]
        if (query[0] === 1) {
            let l = query[1];
            let r = query[2];
            let maxProd = 0;

            // find all possible paris
            for (let i = l; i < r; i++) {
                for (let j = i + 1; j <= r; j++) {
                    maxProd = Math.max(maxProd, arr[i] * arr[j]);
                }
            }

            res.push(maxProd);
        }

        // else update the value of arr[i]
        else if (query[0] === 2) {
            let i = query[1];
            let x = query[2];
            arr[i] = x;
        }
    }

    return res;
}

let arr = [1, 3, 4, 2, 5];
let queries = [[1, 0, 2], [2, 1, 6], [1, 0, 2]];
let res = solveQueries(arr, queries);
for (let i of res) {
    process.stdout.write(i + " ");
}

Output
12 24 

[Expected Approach] - Using Segment Tree - O(q * log n) Time and O(n) Space

The idea is to use a segment tree where each node stores the largest and second largest elements within its corresponding segment. When a range query is performed, the maximum product is calculated by multiplying the two largest elements within that range. This approach ensures efficient query and update operations in logarithmic time.

Follow the below given steps:

  • Define a structure to store the largest and second largest elements at each node of the segment tree.
  • Build the segment tree from the input array, storing values in a bottom-up manner.
  • For a query to find the maximum product in a range [L, R], traverse the segment tree and merge results from overlapping segments, selecting the two largest elements.
  • Compute the product of the two values retrieved and store the result.
  • For an update operation, traverse to the specific index and update the value in the segment tree, then adjust the parent nodes accordingly.
  • Collect results from all queries of type 1 and return them.

Below is given the implementation:

C++
#include <bits/stdc++.h>
using namespace std;

// structure defined
class segment {
public:

    // l for largest
    // sl for second largest
    int l;
    int sl;
};

// function to perform queries
segment processQuery(segment* tree, 
    int index, int s, int e, int qs, int qe) {

    segment res;
    res.l = -1;
    res.sl = -1;

    // no overlapping case
    if (qs > e || qe < s || s > e) {
        return res;
    }

    // complete overlap case
    if (s >= qs && e <= qe) {
        return tree[index];
    }

    // partial overlap case
    int mid = (s + e) / 2;

    // calling left node and right node
    segment left = processQuery(tree, 2 * index, s, mid, qs, qe);
    segment right
        = processQuery(tree, 2 * index + 1, mid + 1, e, qs, qe);

    // largest of ( left.l, right.l)
    int largest = max(left.l, right.l);

    // compute second largest
    // second largest will be minimum
    // of maximum from left and right node
    int second_largest
        = min(max(left.l, right.sl), max(right.l, left.sl));

    // store largest and
    // second_largest in res
    res.l = largest;
    res.sl = second_largest;

    // return the resulting node
    return res;
}

// function to update the query
void update(segment* tree, int index, 
            int s, int e, int i, int val) {

    // no overlapping case
    if (i < s || i > e) {
        return;
    }

    // reached leaf node
    if (s == e) {
        tree[index].l = val;
        tree[index].sl = INT_MIN;
        return;
    }

    // partial overlap
    int mid = (s + e) / 2;

    // left subtree call
    update(tree, 2 * index, s, mid, i, val);

    // right subtree call
    update(tree, 2 * index + 1, mid + 1, e, i, val);

    // largest of ( left.l, right.l)
    tree[index].l
        = max(tree[2 * index].l, tree[2 * index + 1].l);

    // compute second largest
    // second largest will be
    // minimum of maximum from left and right node
    tree[index].sl = min(
        max(tree[2 * index].l, tree[2 * index + 1].sl),
        max(tree[2 * index + 1].l, tree[2 * index].sl));
}

// Function to build the tree
void buildtree(segment* tree, vector<int> &arr, 
                        int index, int s, int e) {

    // tree is build bottom to up
    if (s > e) {
        return;
    }

    // leaf node
    if (s == e) {
        tree[index].l = arr[s];
        tree[index].sl = INT_MIN;
        return;
    }

    int mid = (s + e) / 2;

    // calling the left node
    buildtree(tree, arr, 2 * index, s, mid);

    // calling the right node
    buildtree(tree, arr, 2 * index + 1, mid + 1, e);

    // largest of ( left.l, right.l)
    int largest
        = max(tree[2 * index].l, tree[2 * index + 1].l);

    // compute second largest
    // second largest will be minimum
    // of maximum from left and right node
    int second_largest = min(
        max(tree[2 * index].l, tree[2 * index + 1].sl),
        max(tree[2 * index + 1].l, tree[2 * index].sl));

    // storing the largest and
    // second_largest values in the current node
    tree[index].l = largest;
    tree[index].sl = second_largest;
}

vector<int> solveQueries(vector<int> &arr, 
                vector<vector<int>> &queries) {
    int n = arr.size();

    // to store the result of query of type 1
    vector<int> res;
    
    // allocating memory for segment tree
    segment* tree = new segment[4 * n + 1];

    // buildtree(tree, arr, index, start, end)
    buildtree(tree, arr, 1, 0, n - 1);

    for(auto query: queries) {

        // to find the maximum 
        // product in the range [L, R]
        if(query[0] == 1) {
            int l = query[1];
            int r = query[2];

            // storing the resulting node
            segment ans = processQuery(tree, 1, 0, n - 1, l, r);
            ans.l *= ans.sl;
            res.push_back(ans.l);
        }

        // else update the value of arr[i]
        else if(query[0] == 2) {
            int i = query[1];
            int x = query[2];
            update(tree, 1, 0, n - 1, i, x);
        }
    }

    return res;
}

int main() {
    vector<int> arr = {1, 3, 4, 2, 5};
    vector<vector<int>> queries = 
    { {1, 0, 2}, {2, 1, 6}, {1, 0, 2}};
    vector<int> res = solveQueries(arr, queries);
    for(auto i:res) {
        cout << i << " ";
    }
    return 0;
}
Java
import java.util.*;

class GfG {

    public static class segment {
        public int l;
        public int sl;
    }

    public static segment processQuery(segment[] tree, 
        int index, int s, int e, int qs, int qe) {

        segment res = new segment();
        res.l = -1;
        res.sl = -1;

        // no overlapping case
        if (qs > e || qe < s || s > e) {
            return res;
        }

        // complete overlap case
        if (s >= qs && e <= qe) {
            return tree[index];
        }

        // partial overlap case
        int mid = (s + e) / 2;

        segment left = processQuery(tree, 2 * index, s, mid, qs, qe);
        segment right
            = processQuery(tree, 2 * index + 1, mid + 1, e, qs, qe);

        int largest = Math.max(left.l, right.l);

        int second_largest
            = Math.min(Math.max(left.l, left.sl), Math.max(right.l, left.sl));

        res.l = largest;
        res.sl = second_largest;

        return res;
    }

    public static void update(segment[] tree, int index, 
                int s, int e, int i, int val) {

        // no overlapping case
        if (i < s || i > e) {
            return;
        }

        // reached leaf node
        if (s == e) {
            tree[index].l = val;
            tree[index].sl = Integer.MIN_VALUE;
            return;
        }

        int mid = (s + e) / 2;

        update(tree, 2 * index, s, mid, i, val);

        update(tree, 2 * index + 1, mid + 1, e, i, val);

        tree[index].l
            = Math.max(tree[2 * index].l, tree[2 * index + 1].l);

        tree[index].sl = Math.min(
            Math.max(tree[2 * index].l, tree[2 * index + 1].sl),
            Math.max(tree[2 * index + 1].l, tree[2 * index].sl));
    }

    public static void buildtree(segment[] tree, ArrayList<Integer> arr, 
                            int index, int s, int e) {

        if (s > e) {
            return;
        }

        // leaf node
        if (s == e) {
            tree[index].l = arr.get(s);
            tree[index].sl = Integer.MIN_VALUE;
            return;
        }

        int mid = (s + e) / 2;

        buildtree(tree, arr, 2 * index, s, mid);

        buildtree(tree, arr, 2 * index + 1, mid + 1, e);

        int largest
            = Math.max(tree[2 * index].l, tree[2 * index + 1].l);

        int second_largest = Math.min(
            Math.max(tree[2 * index].l, tree[2 * index + 1].sl),
            Math.max(tree[2 * index + 1].l, tree[2 * index].sl));

        tree[index].l = largest;
        tree[index].sl = second_largest;
    }

    public static ArrayList<Integer> solveQueries(ArrayList<Integer> arr, ArrayList<ArrayList<Integer>> queries) {
        int n = arr.size();

        // to store the result of query of type 1
        ArrayList<Integer> res = new ArrayList<>();

        segment[] tree = new segment[4 * n + 1];
        for (int i = 0; i < tree.length; i++) {
            tree[i] = new segment();
        }

        buildtree(tree, arr, 1, 0, n - 1);

        for (ArrayList<Integer> query : queries) {

            // to find the maximum 
            // product in the range [L, R]
            if (query.get(0) == 1) {
                int l = query.get(1);
                int r = query.get(2);

                segment ans = processQuery(tree, 1, 0, n - 1, l, r);
                ans.l *= ans.sl;
                res.add(ans.l);
            }

            // else update the value of arr[i]
            else if (query.get(0) == 2) {
                int i = query.get(1);
                int x = query.get(2);
                update(tree, 1, 0, n - 1, i, x);
            }
        }

        return res;
    }

    public static void main(String[] args) {
        ArrayList<Integer> arr = new ArrayList<>(Arrays.asList(1, 3, 4, 2, 5));
        ArrayList<ArrayList<Integer>> queries = new ArrayList<>();
        queries.add(new ArrayList<>(Arrays.asList(1, 0, 2)));
        queries.add(new ArrayList<>(Arrays.asList(2, 1, 6)));
        queries.add(new ArrayList<>(Arrays.asList(1, 0, 2)));
        ArrayList<Integer> res = solveQueries(arr, queries);
        for (int i : res) {
            System.out.print(i + " ");
        }
    }
}
Python
class segment:
    def __init__(self):
        self.l = 0
        self.sl = 0

def processQuery(tree, 
    index, s, e, qs, qe):

    res = segment()
    res.l = -1
    res.sl = -1

    # no overlapping case
    if qs > e or qe < s or s > e:
        return res

    # complete overlap case
    if s >= qs and e <= qe:
        return tree[index]

    # partial overlap case
    mid = (s + e) // 2

    left = processQuery(tree, 2 * index, s, mid, qs, qe)
    right = processQuery(tree, 2 * index + 1, mid + 1, e, qs, qe)

    largest = max(left.l, right.l)

    second_largest = min(max(left.l, left.sl), max(right.l, left.sl))

    res.l = largest
    res.sl = second_largest

    return res

def update(tree, index, 
            s, e, i, val):

    # no overlapping case
    if i < s or i > e:
        return

    # reached leaf node
    if s == e:
        tree[index].l = val
        tree[index].sl = float('-inf')
        return

    mid = (s + e) // 2

    update(tree, 2 * index, s, mid, i, val)

    update(tree, 2 * index + 1, mid + 1, e, i, val)

    tree[index].l = max(tree[2 * index].l, tree[2 * index + 1].l)

    tree[index].sl = min(
        max(tree[2 * index].l, tree[2 * index + 1].sl),
        max(tree[2 * index + 1].l, tree[2 * index].sl))

def buildtree(tree, arr, 
                        index, s, e):

    if s > e:
        return

    # leaf node
    if s == e:
        tree[index].l = arr[s]
        tree[index].sl = float('-inf')
        return

    mid = (s + e) // 2

    buildtree(tree, arr, 2 * index, s, mid)

    buildtree(tree, arr, 2 * index + 1, mid + 1, e)

    largest = max(tree[2 * index].l, tree[2 * index + 1].l)

    second_largest = min(
        max(tree[2 * index].l, tree[2 * index + 1].sl),
        max(tree[2 * index + 1].l, tree[2 * index].sl))

    tree[index].l = largest
    tree[index].sl = second_largest

def solveQueries(arr, queries):
    n = len(arr)

    # to store the result of query of type 1
    res = []

    tree = [segment() for _ in range(4 * n + 1)]
    buildtree(tree, arr, 1, 0, n - 1)

    for query in queries:

        # to find the maximum 
        # product in the range [L, R]
        if query[0] == 1:
            l = query[1]
            r = query[2]

            ans = processQuery(tree, 1, 0, n - 1, l, r)
            ans.l *= ans.sl
            res.append(ans.l)

        # else update the value of arr[i]
        elif query[0] == 2:
            i = query[1]
            x = query[2]
            update(tree, 1, 0, n - 1, i, x)

    return res

if __name__ == "__main__":
    arr = [1, 3, 4, 2, 5]
    queries = [[1, 0, 2], [2, 1, 6], [1, 0, 2]]
    res = solveQueries(arr, queries)
    for i in res:
        print(i, end=" ")
C#
using System;
using System.Collections.Generic;

class GfG {

    public class segment {
        public int l;
        public int sl;
    }

    public static segment processQuery(segment[] tree, 
        int index, int s, int e, int qs, int qe) {

        segment res = new segment();
        res.l = -1;
        res.sl = -1;

        // no overlapping case
        if (qs > e || qe < s || s > e) {
            return res;
        }

        // complete overlap case
        if (s >= qs && e <= qe) {
            return tree[index];
        }

        // partial overlap case
        int mid = (s + e) / 2;

        segment left = processQuery(tree, 2 * index, s, mid, qs, qe);
        segment right
            = processQuery(tree, 2 * index + 1, mid + 1, e, qs, qe);

        int largest = Math.Max(left.l, right.l);

        int second_largest
            = Math.Min(Math.Max(left.l, left.sl), 
            Math.Max(right.l, left.sl));

        res.l = largest;
        res.sl = second_largest;

        return res;
    }

    public static void update(segment[] tree, int index, 
                int s, int e, int i, int val) {

        // no overlapping case
        if (i < s || i > e) {
            return;
        }

        // reached leaf node
        if (s == e) {
            tree[index].l = val;
            tree[index].sl = int.MinValue;
            return;
        }

        int mid = (s + e) / 2;

        update(tree, 2 * index, s, mid, i, val);

        update(tree, 2 * index + 1, mid + 1, e, i, val);

        tree[index].l
            = Math.Max(tree[2 * index].l, tree[2 * index + 1].l);

        tree[index].sl = Math.Min(
            Math.Max(tree[2 * index].l, tree[2 * index + 1].sl),
            Math.Max(tree[2 * index + 1].l, tree[2 * index].sl));
    }

    public static void buildtree(segment[] tree, List<int> arr, 
                            int index, int s, int e) {

        if (s > e) {
            return;
        }

        // leaf node
        if (s == e) {
            tree[index].l = arr[s];
            tree[index].sl = int.MinValue;
            return;
        }

        int mid = (s + e) / 2;

        buildtree(tree, arr, 2 * index, s, mid);

        buildtree(tree, arr, 2 * index + 1, mid + 1, e);

        int largest
            = Math.Max(tree[2 * index].l, tree[2 * index + 1].l);

        int second_largest = Math.Min(
            Math.Max(tree[2 * index].l, tree[2 * index + 1].sl),
            Math.Max(tree[2 * index + 1].l, tree[2 * index].sl));

        tree[index].l = largest;
        tree[index].sl = second_largest;
    }

    public static List<int> solveQueries(
        List<int> arr, List<List<int>> queries) {
        int n = arr.Count;

        // to store the result of query of type 1
        List<int> res = new List<int>();

        segment[] tree = new segment[4 * n + 1];
        for (int i = 0; i < tree.Length; i++) {
            tree[i] = new segment();
        }

        buildtree(tree, arr, 1, 0, n - 1);

        foreach (var query in queries) {

            // to find the maximum 
            // product in the range [L, R]
            if (query[0] == 1) {
                int l = query[1];
                int r = query[2];

                segment ans = processQuery(tree, 1, 0, n - 1, l, r);
                ans.l *= ans.sl;
                res.Add(ans.l);
            }

            // else update the value of arr[i]
            else if (query[0] == 2) {
                int i = query[1];
                int x = query[2];
                update(tree, 1, 0, n - 1, i, x);
            }
        }

        return res;
    }

    public static void Main() {
        List<int> arr = new List<int> {1, 3, 4, 2, 5};
        List<List<int>> queries = new List<List<int>> {
            new List<int> {1, 0, 2},
            new List<int> {2, 1, 6},
            new List<int> {1, 0, 2}
        };
        List<int> res = solveQueries(arr, queries);
        foreach (int i in res) {
            Console.Write(i + " ");
        }
    }
}
JavaScript
class segment {
    constructor() {
        this.l = 0;
        this.sl = 0;
    }
}

function processQuery(tree, 
    index, s, e, qs, qe) {

    let res = new segment();
    res.l = -1;
    res.sl = -1;

    // no overlapping case
    if (qs > e || qe < s || s > e) {
        return res;
    }

    // complete overlap case
    if (s >= qs && e <= qe) {
        return tree[index];
    }

    // partial overlap case
    let mid = Math.floor((s + e) / 2);

    let left = processQuery(tree, 2 * index, s, mid, qs, qe);
    let right = processQuery(tree, 2 * index + 1, mid + 1, e, qs, qe);

    let largest = Math.max(left.l, right.l);

    let second_largest = Math.min(
        Math.max(left.l, left.sl), Math.max(right.l, left.sl)
    );

    res.l = largest;
    res.sl = second_largest;

    return res;
}

function update(tree, index, 
            s, e, i, val) {

    // no overlapping case
    if (i < s || i > e) {
        return;
    }

    // reached leaf node
    if (s === e) {
        tree[index].l = val;
        tree[index].sl = Number.MIN_SAFE_INTEGER;
        return;
    }

    let mid = Math.floor((s + e) / 2);

    update(tree, 2 * index, s, mid, i, val);

    update(tree, 2 * index + 1, mid + 1, e, i, val);

    tree[index].l = Math.max(tree[2 * index].l, tree[2 * index + 1].l);

    tree[index].sl = Math.min(
        Math.max(tree[2 * index].l, tree[2 * index + 1].sl),
        Math.max(tree[2 * index + 1].l, tree[2 * index].sl)
    );
}

function buildtree(tree, arr, 
                        index, s, e) {

    if (s > e) {
        return;
    }

    // leaf node
    if (s === e) {
        tree[index].l = arr[s];
        tree[index].sl = Number.MIN_SAFE_INTEGER;
        return;
    }

    let mid = Math.floor((s + e) / 2);

    buildtree(tree, arr, 2 * index, s, mid);

    buildtree(tree, arr, 2 * index + 1, mid + 1, e);

    let largest = Math.max(tree[2 * index].l, tree[2 * index + 1].l);

    let second_largest = Math.min(
        Math.max(tree[2 * index].l, tree[2 * index + 1].sl),
        Math.max(tree[2 * index + 1].l, tree[2 * index].sl)
    );

    tree[index].l = largest;
    tree[index].sl = second_largest;
}

function solveQueries(arr, queries) {
    let n = arr.length;

    // to store the result of query of type 1
    let res = [];

    let tree = new Array(4 * n + 1).fill(null).map(() => new segment());
    buildtree(tree, arr, 1, 0, n - 1);

    for (let query of queries) {

        // to find the maximum 
        // product in the range [L, R]
        if (query[0] === 1) {
            let l = query[1];
            let r = query[2];

            let ans = processQuery(tree, 1, 0, n - 1, l, r);
            ans.l *= ans.sl;
            res.push(ans.l);
        }

        // else update the value of arr[i]
        else if (query[0] === 2) {
            let i = query[1];
            let x = query[2];
            update(tree, 1, 0, n - 1, i, x);
        }
    }

    return res;
}

let arr = [1, 3, 4, 2, 5];
let queries = [[1, 0, 2], [2, 1, 6], [1, 0, 2]];
let res = solveQueries(arr, queries);
for (let i of res) {
    process.stdout.write(i + " ");
}

Output
12 24 

Next Article

Similar Reads