给定一个由N个正整数组成的数组。任务是根据给定的查询类型执行以下操作。
1.在给定范围内打印最大成对产品。 [LR]
2.用一些给定值更新A i。
例子:
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.
天真的解决方案:蛮力方法是从L遍历到R并检查每对,然后找到其中的最大乘积对。
时间复杂度:每个查询为O(N ^ 2)。
更好的解决方案是遍历然后返回它们的乘积来找到L到R范围内的第一个和第二个最大数字。
时间复杂度:每个查询为O(N)。
一种有效的解决方案是使用段树将最大和第二大数目存储在节点中,然后返回它们的乘积。
下面是上述方法的实现。
// C++ program to find the maximum
// product in a range with updates
#include
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
时间复杂度:每个查询的O(log N)和用于构建树的O(N)。