📌  相关文章
📜  查询以更新范围来计算索引[L,R]范围内的数组元素的平方和

📅  最后修改于: 2021-04-17 10:12:20             🧑  作者: Mango

给定一个由N个整数组成的数组arr [] ,一个整数X和一个由以下两种类型的查询组成的2D数组query [] []:

  • (L,R,0):将[L,R]范围内的所有数组元素增加一个值X。
  • (L,R,1):在[L,R]范围内将所有数组元素设置为X。
  • (L,R,2):打印 元素在[L,R]范围内的平方和。

例子:

天真的方法:最简单的方法是在每个查询的给定范围内遍历给定数组,并在给定数组上执行相应的查询并相应地打印结果。

下面是上述方法的实现:

C++
// C++ program for the above approach
  
#include 
using namespace std;
  
// Function to find the sum of squares
// of elements present in the range of
// indices [l, r] in the array v[]
long long rangesum(vector& v,
                   int l, int r)
{
    long long sum = 0;
  
    // Iterate over range l to r
    for (int i = l; i <= r; i++) {
  
        // Add square of current
        // element to the sum
        sum += v[i] * v[i];
    }
  
    // Return the sum
    return sum;
}
  
// Function to perform given queries
void rangeQuery(vector& v, int l,
                int r, int update,
                int type)
{
    // For type 1 update
    if (type == 1) {
  
        // Iterate over range l to r
        // and update the array elements
        for (int i = l; i <= r; i++) {
            v[i] = update;
        }
    }
  
    // For type 0 update
    else {
  
        // Iterate over range l to r
        // and update the elements
        for (int i = l; i <= r; i++) {
            v[i] += update;
        }
    }
}
  
// Function to print the result
// for the given queries
void printAnswer(vector > query,
                 vector a, int X)
{
  
    // Iterate over the query[]
    for (int i = 0;
         i < query.size(); i++) {
  
        int l = query[i][0];
        int r = query[i][1];
        if (query[i][2] == 0) {
  
            // Add by X modified array
            // will be considered for
            // the operation
            rangeQuery(a, l, r, X, 0);
        }
        else if (query[i][2] == 1) {
  
            // Substitute by X
            rangeQuery(a, l, r, X, 1);
        }
        else {
  
            // Print the range sum
            cout << rangesum(a, l, r)
                 << " ";
        }
    }
}
  
// Driver Code
int main()
{
    vector arr = { 1, 2, 3, 4, 5 };
    int X = 2;
    vector > query = {
        { 1, 3, 0 }, { 1, 2, 2 },
        { 3, 4, 1 }, { 2, 3, 2 }
    };
  
    printAnswer(query, arr, X);
  
    return 0;
}


C++
// C++ program of the above approach
  
#include 
using namespace std;
  
// Used to create Segment Tree
vector seg(400000, 0),
    dseg(400000, 0),
    a(100000);
  
// Stores the segment sum
vector segSum(400000, 0);
  
// Building the segment tree
void build(int ind, int low, int high)
{
    // If low is the same as high
    if (low == high) {
  
        // Update the segment node
        seg[ind] = a[low] * a[low];
        segSum[ind] = a[low];
        return;
    }
  
    // Find the mid
    int mid = (low + high) / 2;
  
    // Recursively call for
    // the two halves of the tree
    build(2 * ind + 1, low, mid);
    build(2 * ind + 2, mid + 1, high);
  
    // Update the segment node
    seg[ind] = seg[2 * ind + 1]
               + seg[2 * ind + 2];
  
    // Update the segment sum
    segSum[ind] = segSum[2 * ind + 1]
                  + segSum[2 * ind + 2];
}
  
// Function to find the sum of squares
// of array elements in the given range
long long rangesum(int ind, int low,
                   int high, int l,
                   int r)
{
    // Pending updates if any
    if (dseg[ind] != 0) {
  
        // Update the square
        // over segment node
        seg[ind] += (high - low + 1)
                        * dseg[ind]
                        * dseg[ind]
                    + (2 * dseg[ind]
                       * segSum[ind]);
  
        // Update the square over
        // the segment sum
        segSum[ind] += (high - low + 1)
                       * dseg[ind];
  
        // If low and high are different
        if (low != high) {
            dseg[2 * ind + 1] += dseg[ind];
            dseg[2 * ind + 2] += dseg[ind];
        }
        dseg[ind] = 0;
    }
  
    // Out of bounds
    if (r < low || l > high
        || low > high) {
        return 0;
    }
  
    // Completely within the range
    if (l <= low && r >= high) {
        return seg[ind];
    }
  
    // Partially overlapping
    int mid = (low + high) / 2;
  
    // Return the range sum
    return rangesum(2 * ind + 1,
                    low, mid, l, r)
           + rangesum(2 * ind + 2,
                      mid + 1, high,
                      l, r);
}
  
// Function to perform the given queries
void rangeQuery(int ind, int low,
                int high, int l, int r,
                int update, int type)
{
    // Pending updates if any
    if (dseg[ind] != 0) {
  
        // Update the segment node
        seg[ind]
            += (high - low + 1)
               * dseg[ind] * dseg[ind];
  
        // Update the segment sum
        segSum[ind] += (high - low + 1)
                       * dseg[ind];
  
        if (low != high) {
            dseg[2 * ind + 1] += dseg[ind];
            dseg[2 * ind + 2] += dseg[ind];
        }
  
        dseg[ind] = 0;
    }
  
    // Out of bounds
    if (r < low || l > high
        || low > high) {
        return;
    }
  
    // Completely within the range
    if (l <= low && r >= high) {
  
        // Substitute with X
        if (type == 1) {
  
            // Updating the current
            // index for sum of square
            seg[ind] = (high - low + 1)
                       * update * update;
  
            // Updating the current
            // index for sum
            segSum[ind] = (high - low + 1)
                          * update;
        }
        else {
  
            // Add X updating the current
            // index for sum of square
            seg[ind] += (high - low + 1)
                            * update * update
                        + 2 * update
                              * segSum[ind];
  
            // Updating the current
            // index for sum
            segSum[ind] += (high - low + 1)
                           * update;
        }
  
        // Lazy update
        if (low != high) {
            dseg[2 * ind + 1] += update;
            dseg[2 * ind + 2] += update;
        }
        return;
    }
  
    // Partially overlapping
    int mid = (low + high) / 2;
    rangeQuery(2 * ind + 1, low,
               mid, l, r, update,
               type);
  
    rangeQuery(2 * ind + 2, mid + 1,
               high, l, r, update,
               type);
  
    // Updating sum of squares
    // and sum while bactracking
    seg[ind] = seg[2 * ind + 1]
               + seg[2 * ind + 2];
  
    segSum[ind] = segSum[2 * ind + 1]
                  + segSum[2 * ind + 2];
}
  
// Function to print the answer
// for the given queries
void printAnswer(
    vector > query,
    int N, int X)
{
    // Build Segment tree
    build(0, 0, N - 1);
  
    // Traverse queries
    for (int i = 0;
         i < query.size(); i++) {
  
        int l = query[i][0];
        int r = query[i][1];
        if (query[i][2] == 0) {
  
            // Add by X, modified
            // array will be considered
            // for operation
            rangeQuery(0, 0, N - 1, l, r, X, 0);
        }
        else if (query[i][2] == 1) {
  
            // Substitute by X modified
            // array will be considered
            // for operation
            rangeQuery(0, 0, N - 1,
                       l, r, X, 1);
        }
        else {
            cout << rangesum(0, 0, N - 1,
                             l, r)
                 << " ";
        }
    }
}
  
// Driver Code
int main()
{
    a = { 1, 2, 3, 4 };
    int X = 2;
    int N = (int)a.size();
  
    // Given queries
    vector > query = {
        { 1, 3, 0 }, { 1, 2, 2 },
        { 3, 3, 1 }, { 2, 3, 2 }
    };
  
    printAnswer(query, N, X);
  
    return 0;
}


输出:
41 29

时间复杂度: O(Q * N)
辅助空间: O(N + Q)

高效方法:可以使用段树来优化上述方法。请按照以下步骤解决问题:

  • 初始化两个数组seg []segSum [] ,其中seg []存储平方和,而segSum []存储范围[L,R]中的元素之和。
  • 由于以下原因,存储数组元素的总和:
    • 考虑以下示例, arr [] = {a,b,c,d,e},范围= {1,3},X =K。
    • 在给定范围[1,3]中将每个元素增加K时,该值变为:
  • 在此范围内将X = K替换为(K) 2 +(K) 2 +(K) 2 = 3 * K 2 ,可以将其推广为:(高–低+ 1)* X *X
  • 使用上述公式更新范围[L,R]内的数组元素的平方和,并为每个类型2的查询相应地打印范围和。

下面是上述方法的实现:

C++

// C++ program of the above approach
  
#include 
using namespace std;
  
// Used to create Segment Tree
vector seg(400000, 0),
    dseg(400000, 0),
    a(100000);
  
// Stores the segment sum
vector segSum(400000, 0);
  
// Building the segment tree
void build(int ind, int low, int high)
{
    // If low is the same as high
    if (low == high) {
  
        // Update the segment node
        seg[ind] = a[low] * a[low];
        segSum[ind] = a[low];
        return;
    }
  
    // Find the mid
    int mid = (low + high) / 2;
  
    // Recursively call for
    // the two halves of the tree
    build(2 * ind + 1, low, mid);
    build(2 * ind + 2, mid + 1, high);
  
    // Update the segment node
    seg[ind] = seg[2 * ind + 1]
               + seg[2 * ind + 2];
  
    // Update the segment sum
    segSum[ind] = segSum[2 * ind + 1]
                  + segSum[2 * ind + 2];
}
  
// Function to find the sum of squares
// of array elements in the given range
long long rangesum(int ind, int low,
                   int high, int l,
                   int r)
{
    // Pending updates if any
    if (dseg[ind] != 0) {
  
        // Update the square
        // over segment node
        seg[ind] += (high - low + 1)
                        * dseg[ind]
                        * dseg[ind]
                    + (2 * dseg[ind]
                       * segSum[ind]);
  
        // Update the square over
        // the segment sum
        segSum[ind] += (high - low + 1)
                       * dseg[ind];
  
        // If low and high are different
        if (low != high) {
            dseg[2 * ind + 1] += dseg[ind];
            dseg[2 * ind + 2] += dseg[ind];
        }
        dseg[ind] = 0;
    }
  
    // Out of bounds
    if (r < low || l > high
        || low > high) {
        return 0;
    }
  
    // Completely within the range
    if (l <= low && r >= high) {
        return seg[ind];
    }
  
    // Partially overlapping
    int mid = (low + high) / 2;
  
    // Return the range sum
    return rangesum(2 * ind + 1,
                    low, mid, l, r)
           + rangesum(2 * ind + 2,
                      mid + 1, high,
                      l, r);
}
  
// Function to perform the given queries
void rangeQuery(int ind, int low,
                int high, int l, int r,
                int update, int type)
{
    // Pending updates if any
    if (dseg[ind] != 0) {
  
        // Update the segment node
        seg[ind]
            += (high - low + 1)
               * dseg[ind] * dseg[ind];
  
        // Update the segment sum
        segSum[ind] += (high - low + 1)
                       * dseg[ind];
  
        if (low != high) {
            dseg[2 * ind + 1] += dseg[ind];
            dseg[2 * ind + 2] += dseg[ind];
        }
  
        dseg[ind] = 0;
    }
  
    // Out of bounds
    if (r < low || l > high
        || low > high) {
        return;
    }
  
    // Completely within the range
    if (l <= low && r >= high) {
  
        // Substitute with X
        if (type == 1) {
  
            // Updating the current
            // index for sum of square
            seg[ind] = (high - low + 1)
                       * update * update;
  
            // Updating the current
            // index for sum
            segSum[ind] = (high - low + 1)
                          * update;
        }
        else {
  
            // Add X updating the current
            // index for sum of square
            seg[ind] += (high - low + 1)
                            * update * update
                        + 2 * update
                              * segSum[ind];
  
            // Updating the current
            // index for sum
            segSum[ind] += (high - low + 1)
                           * update;
        }
  
        // Lazy update
        if (low != high) {
            dseg[2 * ind + 1] += update;
            dseg[2 * ind + 2] += update;
        }
        return;
    }
  
    // Partially overlapping
    int mid = (low + high) / 2;
    rangeQuery(2 * ind + 1, low,
               mid, l, r, update,
               type);
  
    rangeQuery(2 * ind + 2, mid + 1,
               high, l, r, update,
               type);
  
    // Updating sum of squares
    // and sum while bactracking
    seg[ind] = seg[2 * ind + 1]
               + seg[2 * ind + 2];
  
    segSum[ind] = segSum[2 * ind + 1]
                  + segSum[2 * ind + 2];
}
  
// Function to print the answer
// for the given queries
void printAnswer(
    vector > query,
    int N, int X)
{
    // Build Segment tree
    build(0, 0, N - 1);
  
    // Traverse queries
    for (int i = 0;
         i < query.size(); i++) {
  
        int l = query[i][0];
        int r = query[i][1];
        if (query[i][2] == 0) {
  
            // Add by X, modified
            // array will be considered
            // for operation
            rangeQuery(0, 0, N - 1, l, r, X, 0);
        }
        else if (query[i][2] == 1) {
  
            // Substitute by X modified
            // array will be considered
            // for operation
            rangeQuery(0, 0, N - 1,
                       l, r, X, 1);
        }
        else {
            cout << rangesum(0, 0, N - 1,
                             l, r)
                 << " ";
        }
    }
}
  
// Driver Code
int main()
{
    a = { 1, 2, 3, 4 };
    int X = 2;
    int N = (int)a.size();
  
    // Given queries
    vector > query = {
        { 1, 3, 0 }, { 1, 2, 2 },
        { 3, 3, 1 }, { 2, 3, 2 }
    };
  
    printAnswer(query, N, X);
  
    return 0;
}
输出:
41 29

时间复杂度: O(Q * log N)
辅助空间: O(N)