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.