Related Articles

# Queries to find maximum product pair in range with updates

• Difficulty Level : Hard
• Last Updated : 17 Aug, 2018

Given an array of N positive integers. The task is to perform the following operations according to the type of query given.
1. Print the maximum pair product in a given range. [L-R]
2. Update Ai with some given value.

Examples:

Input: A={1, 3, 4, 2, 5}
Queries:
Type 1: L = 0, R = 2.
Type 2: i = 1, val = 6
Type 1: L = 0, R = 2.

Output:
12
24

For the query1, the maximum product in a range [0, 2] is 3*4 = 12.
For the query2, after an update, the array becomes [1, 6, 4, 2, 5]
For the query3, the maximum product in a range [0, 2] is 6*4 = 24.

## Recommended: Please try your approach on {IDE} first, before moving on to the solution.

Naive Solution: The brute force approach is to traverse from L to R and check for every pair and then find the maximum product pair among them.
Time Complexity: O(N^2) for every query.

A better solution is to find the first and the second largest number in the range L to R by traversing and then returning their product.
Time Complexity: O(N) for every query.

A efficient solution is to use a segment tree to store the largest and second largest number in the nodes and then return the product of them.

Below is the implementation of above approach.

 // C++ program to find the maximum// product in a range with updates#include using namespace std;#define ll long long  // structure definedstruct segment {    // l for largest    // sl for second largest    ll l;    ll sl;};  // function to perform queriessegment query(segment* tree, ll index,              ll s, ll e, ll qs, ll 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    ll mid = (s + e) / 2;      // calling left node and right node    segment left = query(tree, 2 * index,                         s, mid, qs, qe);    segment right = query(tree, 2 * index + 1,                          mid + 1, e, qs, qe);      // largest of ( left.l, right.l)    ll largest = max(left.l, right.l);      // compute second largest    // second largest will be minimum    // of maximum from left and right node    ll 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;}  // funcntion to update the queryvoid update(segment* tree, ll index,            ll s, ll e, ll i, ll 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      ll 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 treevoid buildtree(segment* tree, ll* a, ll index, ll s, ll e){    // tree is build bottom to up    if (s > e) {        return;    }      // leaf node    if (s == e) {        tree[index].l = a[s];        tree[index].sl = INT_MIN;        return;    }      ll mid = (s + e) / 2;      // calling the left node    buildtree(tree, a, 2 * index, s, mid);      // calling the right node    buildtree(tree, a, 2 * index + 1, mid + 1, e);      // largest of ( left.l, right.l)    ll 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    ll 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;}  // Driver Codeint main(){      // your code goes here    ll n = 5;      ll a[5] = { 1, 3, 4, 2, 5 };      // allocating memory for segment tree    segment* tree = new segment[4 * n + 1];      // buildtree(tree, a, index, start, end)    buildtree(tree, a, 1, 0, n - 1);      // query section    // storing the resulting node    segment res = query(tree, 1, 0, n - 1, 0, 2);      cout << "Maximum product in the range "         << "0 and 2 before update: " << (res.l * res.sl);      // update section    // update(tree, index, start, end, i, v)    update(tree, 1, 0, n - 1, 1, 6);      res = query(tree, 1, 0, n - 1, 0, 2);      cout << "\nMaximum product in the range "         << "0 and 2 after update: " << (res.l * res.sl);      return 0;}
Output:
Maximum product in the range 0 and 2 before update: 12
Maximum product in the range 0 and 2 after update: 24

Time Complexity: O(log N) per query and O(N) for building the tree.

My Personal Notes arrow_drop_up