在给定范围内所有无序对的乘积之和的更新查询
- 最后更新 : 2021年8月10日
给定一个由N个整数组成的数组A[]和以下类型的Q个查询,任务是打印所有更新查询的输出。
- (1, L, R):第1种类型的查询,寻找数组中从索引L到R的所有无序对的乘积之和,其中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 Rvoid pairwiseProductSum(int a[],int l,int r){int sum = 0;// Loop to iterate over all possible// pairs from L to Rfor (int j = l - 1; j <= r - 1; j++) {for (int k = j + 1; k <= r - 1; k++) {sum += (a[j] * a[k]);}}// Print answercout << sum << endl;}// Function to update the Array// element at index P to Xvoid updateArray(int* a,int p,int x){// Update the value at Pth// index in the arraya[p - 1] = x;}// Function to solve Q queriesvoid solveQueries(int* a,int n,int Q,int query[][3]){for (int i = 0; i < Q; i++) {// If Query is of type 1if (query[i][0] == 1)pairwiseProductSum(a, query[i][1], query[i][2]);// If Query is of type 2elseupdateArray(a, query[i][1], query[i][2]);}}// Driver Codeint 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 typevector<int> bit1(MAXN, 0);// Vector to store fenwick tree// of the 2nd typevector<int> bit2(MAXN, 0);// Function to update the value// at idx index in fenwick treevoid 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 Treeint 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[] Arrayvoid buildFenwickTree(int a[],int n){for (int i = 1; i <= n; i++) {// Function call to update// the ith element in the// first Fenwick Treeupdate(i, a[i - 1], bit1);// Function call to update// the ith element in the// first Fenwick Treeupdate(i, a[i - 1] * a[i - 1], bit2);}}// Function to find the Pairwise// Product Sum in the range L to Rvoid pairwiseProductSum(int a[],int l,int r){int sum, e, q;// Function call to calculate E// in the given rangee = query(r, bit1) - query(l - 1, bit1);e = e * e;// Function call to calculate E// in the given rangeq = query(r, bit2) - query(l - 1, bit2);sum = (e - q) / 2;// Print Answercout << sum << endl;}// Function to update the Fenwick// tree and the array element at// index P to the new value Xvoid updateArray(int* a,int p,int x){// Function call to update the// value in 1st Fenwick Treeupdate(p, -a[p - 1], bit1);update(p, x, bit1);// Function call to update the// value in 2nd Fenwick Treeupdate(p, -a[p - 1] * a[p - 1], bit2);update(p, x * x, bit2);a[p - 1] = x;}// Function to solve Q queriesvoid solveQueries(int* a,int n,int Q,int query[][3]){// Function Call to build the// Fenwick TreebuildFenwickTree(a, n);for (int i = 0; i < Q; i++) {// If Query is of type 1if (query[i][0] == 1)pairwiseProductSum(a, query[i][1], query[i][2]);// If Query is of type 2elseupdateArray(a, query[i][1], query[i][2]);}}// Driver Codeint 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
保存