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
24For 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.
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 <bits/stdc++.h> using namespace std; #define ll long long // structure defined struct segment { // l for largest // sl for second largest ll l; ll sl; }; // function to perform queries segment 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 query void 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 tree void 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 Code int 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; } |
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.