在给定范围内的所有无序对的乘积之和,并进行更新查询

159 阅读5分钟

在给定范围内所有无序对的乘积之和的更新查询

  • 最后更新 : 2021年8月10日

给定一个由N个整数组成的数组A[]和以下类型的Q个查询,任务是打印所有更新查询的输出。

  • (1, L, R):第1种类型的查询,寻找数组中从索引LR所有无序对的乘积之和,其中1<=L<=R<=N。
  • (2, P, X):第2种类型的查询是将数组中P个整数的值改为一个新的值X

例子。

输入。 A[] = {5 7 2 3 1}, Q = 3, Queries[] = [ [1, 1, 3], [2, 2, 5], [1, 2, 5]] 。

输出:
59
41
解释:
查询1:在第1个查询中,给定范围内可能的配对是(5,7),(5,2)和(7,2)。所以成对的乘积之和将是(5*7)+(5*2)+(7*2)=35+10+14=59。
查询2:在第2个查询中,将第2个整数更新为5,这使得数组为[5, 5, 2, 3, 1]。
查询3:在第3个查询中,范围[2, 5]中可能的配对是(5, 2),(5,3),(5, 1),(2, 3),(2, 1)和(3, 1)。这些配对的乘积之和为41。

输入。 A[] = {7 3 2 1 4 5 8}, Q = 5, Queries[] = [ [1, 1, 6], [2, 2, 4], [1, 2, 5], [2, 3, 8], [1, 4, 7] ]

输出。 59
41
6

天真的方法。 解决这个问题的简单方法是:对于第一类查询,在给定的查询范围内生成所有无序的配对,并打印这些配对的乘积之和。对于第二种类型的查询,根据给定的值更新数组元素。

下面是上述方法的实现。

C++

// C++ Program for the above approach
#include <bits/stdc++.h>
using namespace std;
// Function to calculate the Pairwise
// Product Sum in range from L to R
void pairwiseProductSum(int a[],int l,int r)
{
int sum = 0;
// Loop to iterate over all possible
// pairs from L to R
for (int j = l - 1; j <= r - 1; j++) {
for (int k = j + 1; k <= r - 1; k++) {
sum += (a[j] * a[k]);
}
}
// Print answer
cout << sum << endl;
}
// Function to update the Array
// element at index P to X
void updateArray(int* a,int p,int x)
{
// Update the value at Pth
// index in the array
a[p - 1] = x;
}
// Function to solve Q queries
void solveQueries(
int* a,int n,
int Q,int query[][3])
{
for (int i = 0; i < Q; i++) {
// If Query is of type 1
if (query[i][0] == 1)
pairwiseProductSum(
a, query[i][1], query[i][2]);
// If Query is of type 2
else
updateArray(
a, query[i][1], query[i][2]);
}
}
// Driver Code
int main()
{
int A[] = { 5, 7, 2, 3, 1 };
int N =sizeof(A) /sizeof(int);
int Q = 3;
int query[Q][3] = { { 1, 1, 3 },
{ 2, 2, 5 },
{ 1, 2, 5 } };
solveQueries(A, N, Q, query);
return 0;
}

输出。

59
41

时间复杂度。 _O(N2)_用于成对积和查询,O(1) 用于更新查询。
空间复杂度。 O(N)

高效的方法。使这里讨论的前缀和技术,每个查询的复杂度可以降低到_O(N)_ 。

**更好的方法。**进一步降低复杂度的更好方法是使用基于以下观察的Fenwick树

鉴于
(a + b + c)2=a2+b2+c2+ 2*(a*b + b*c + c*a)

让所需的配对产品之和为P

让E = (a1 + a2 + a3 + a4 ... + an)2
=> E = a12 + a22 + ... + an2 + 2*(a1*a2 + a1*a3 + ....)
=> E = a12 +a22+... + an2 + 2*(P)
=> P = ( E - ( a12 + a22 + ....+an2 ) )/ 2

所以,P=(E-Q)/2,其中Q=(a12+a22+....+an2

根据上述观察,我们可以维护两个芬威克树。

  • 第一个芬威克树将通过更新查询来跟踪给定范围内的元素之和。这可以用来计算任何给定范围的E
  • 同样地,第二个芬威克树将通过更新查询来跟踪给定范围内元素的平方之和。这可以用来计算任何给定范围的Q。此后,P可以很容易地被计算为P=(E-Q)/2

下面是上述方法的实现。

C++

// C++ Program for the above approach
#include <bits/stdc++.h>
using namespace std;
#define MAXN 100000
// Vector to store fenwick tree
// of the 1st type
vector<int> bit1(MAXN, 0);
// Vector to store fenwick tree
// of the 2nd type
vector<int> bit2(MAXN, 0);
// Function to update the value
// at idx index in fenwick tree
void update(int idx,int val, vector<int>& bit)
{
while (idx < bit.size()) {
bit[idx] += val;
idx += idx & (-idx);
}
}
// Function to return the sum of values
// stored from O to idx index in the
// array using Fenwick Tree
int query(int idx, vector<int>& bit)
{
int res = 0;
while (idx > 0) {
res += bit[idx];
idx -= idx & (-idx);
}
return res;
}
// Function to build the Fenwick
// tree from the a[] Array
void buildFenwickTree(int a[],int n)
{
for (int i = 1; i <= n; i++) {
// Function call to update
// the ith element in the
// first Fenwick Tree
update(i, a[i - 1], bit1);
// Function call to update
// the ith element in the
// first Fenwick Tree
update(i, a[i - 1] * a[i - 1], bit2);
}
}
// Function to find the Pairwise
// Product Sum in the range L to R
void pairwiseProductSum(int a[],int l,int r)
{
int sum, e, q;
// Function call to calculate E
// in the given range
e = query(r, bit1) - query(l - 1, bit1);
e = e * e;
// Function call to calculate E
// in the given range
q = query(r, bit2) - query(l - 1, bit2);
sum = (e - q) / 2;
// Print Answer
cout << sum << endl;
}
// Function to update the Fenwick
// tree and the array element at
// index P to the new value X
void updateArray(int* a,int p,int x)
{
// Function call to update the
// value in 1st Fenwick Tree
update(p, -a[p - 1], bit1);
update(p, x, bit1);
// Function call to update the
// value in 2nd Fenwick Tree
update(p, -a[p - 1] * a[p - 1], bit2);
update(p, x * x, bit2);
a[p - 1] = x;
}
// Function to solve Q queries
void solveQueries(
int* a,int n,
int Q,int query[][3])
{
// Function Call to build the
// Fenwick Tree
buildFenwickTree(a, n);
for (int i = 0; i < Q; i++) {
// If Query is of type 1
if (query[i][0] == 1)
pairwiseProductSum(
a, query[i][1], query[i][2]);
// If Query is of type 2
else
updateArray(
a, query[i][1], query[i][2]);
}
}
// Driver Code
int main()
{
int A[] = { 5, 7, 2, 3, 1 };
int N =sizeof(A) /sizeof(int);
int Q = 3;
int query[Q][3] = { { 1, 1, 3 },
{ 2, 2, 5 },
{ 1, 2, 5 } };
solveQueries(A, N, Q, query);
return 0;
}

输出。

59
41

时间复杂度。 O(N*log N) 用于构建芬威克树
_O(log N)_用于成对积和查询
O(log N) 用于更新查询。
辅助空间。 O(N)

读者请注意!现在不要停止学习。以学生可接受的价格获得所有重要的DSA概念。 DSA自学课程以适合学生的价格掌握所有重要的DSA概念,并为行业做好准备。 要完成从学习语言到DS Algo以及更多的准备工作,请参考 完整的面试准备课程.

如果你想参加专家的现场课程 ,请参考 面向在职人士的DSA现场课程面向学生的竞争性编程直播课程.

我的个人笔记 arrow_drop_up

保存