📌  相关文章
📜  查询以奇数除数组成的数组元素之和

📅  最后修改于: 2021-05-17 20:42:51             🧑  作者: Mango

给定一个由N个正整数组成的数组arr []和一个由{L,R}形式的Q个查询组成的数组Query [] [2] ,任务是从范围[L, R] ,除数为奇数。

例子:

天真的方法:最简单的方法是解决给定的问题是遍历给定查询范围[L,R]内的给定数组arr []并找到[L,R]范围内具有奇数个元素的元素之和除数,然后打印结果总和。

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

高效的方法:基于以下观察,还可以优化上述方法:

  • 仅当平方数为正数时,除数的数目才为奇数。
  • 因此,可以通过将没有奇数除数的整数替换为0来解决该问题。然后,构建一个分段树,以查找范围内的元素之和来回答查询。

请按照以下步骤解决问题:

  • 遍历给定数组arr [],然后将非理想正方形的整数替换为0
  • 建立一个细分树,以回答范围之间的总和查询。
  • 遍历所有Q个查询,对于每个查询,从细分树中获取特定范围的总和。

下面是上述方法的实现:

C++
// C++ program for the above approach
  
#include 
using namespace std;
  
// Function to get the middle index
// from the given ranges
int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
  
// Recursive function to find the sum
// of values in the given range of
// the array
int getSumUtil(int* st, int ss, int se,
               int qs, int qe, int si)
{
  
    // If segment of this node is a
    // part of given range, then
    // return the sum of the segment
    if (qs <= ss && qe >= se)
        return st[si];
  
    // If segment of this node is
    // outside the given range
    if (se < qs || ss > qe)
        return 0;
  
    // If a part of this segment
    // overlaps the given range
    int mid = getMid(ss, se);
  
    return getSumUtil(st, ss, mid,
                      qs, qe, 2 * si + 1)
           + getSumUtil(st, mid + 1,
                        se, qs, qe,
                        2 * si + 2);
}
  
// Function to find the sum of elements
// in the range from index qs (query
// start) to qe (query end)
int getSum(int* st, int n, int qs, int qe)
{
    // Invalid ranges
    if (qs < 0 || qe > n - 1 || qs > qe) {
        cout << "Invalid Input";
        return -1;
    }
  
    return getSumUtil(st, 0, n - 1, qs, qe, 0);
}
  
// Recursive function to construct the
// Segment Tree for array[ss..se]. si
// is index of current node in tree st
int constructSTUtil(int arr[], int ss,
                    int se, int* st,
                    int si)
{
    // If there is one element
    // in the array
    if (ss == se) {
        st[si] = arr[ss];
        return arr[ss];
    }
  
    int mid = getMid(ss, se);
  
    // Recur for left and right
    // subtrees and store the sum
    // of values in this node
    st[si] = constructSTUtil(arr, ss, mid,
                             st, si * 2 + 1)
             + constructSTUtil(arr, mid + 1,
                               se, st,
                               si * 2 + 2);
    return st[si];
}
  
// Function to construct segment tree
// from the given array
int* constructST(int arr[], int n)
{
    // Allocate memory for the segment
    // tree Height of segment tree
    int x = (int)(ceil(log2(n)));
  
    // Maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
  
    // Allocate memory
    int* st = new int[max_size];
  
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0);
  
    // Return the constructed
    // segment tree
    return st;
}
  
// Function to find the sum of elements
// having odd number of divisors in
// index range [L, R] for Q queries
void OddDivisorsSum(int n, int q, int arr[],
                    vector > Query)
{
    // Traverse the array, arr[]
    for (int i = 0; i < n; i++) {
        int sq = sqrt(arr[i]);
  
        // Replace elements that are
        // not perfect squares with 0
        if (sq * sq != arr[i])
            arr[i] = 0;
    }
  
    // Build segment tree from the
    // given array
    int* st = constructST(arr, n);
  
    // Iterate through all the queries
    for (int i = 0; i < q; i++) {
        int l = Query[i].first;
        int r = Query[i].second;
  
        // Print sum of values in
        // array from index l to r
        cout << getSum(st, n, l, r) << " ";
    }
}
  
// Driver Code
int main()
{
    int arr[] = { 2, 4, 5, 6, 9 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int Q = 3;
    vector > Query
        = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
    OddDivisorsSum(N, Q, arr, Query);
  
    return 0;
}


C++
// C++ program for the above approach
  
#include 
using namespace std;
  
// Function to find the sum of elements
// having odd number of divisors in
// index range [L, R] for Q queries
void OddDivisorsSum(int n, int q, int a[],
                    vector > Query)
{
    // Initialize the dp[] array
    int DP[n] = { 0 };
  
    // Traverse the array, arr[]
    for (int i = 0; i < n; i++) {
        int x = sqrt(a[i]);
  
        // If a[i] is a perfect square,
        // then update value of DP[i] to a[i]
        if (x * x == a[i])
            DP[i] = a[i];
    }
  
    // Find the prefix sum of DP[] array
    for (int i = 1; i < n; i++) {
        DP[i] = DP[i - 1] + DP[i];
    }
  
    // Iterate through all the queries
    for (int i = 0; i < q; i++) {
  
        int l = Query[i].first;
        int r = Query[i].second;
  
        // Find the sum for each query
        if (l == 0) {
            cout << DP[r] << " ";
        }
        else {
            cout << DP[r] - DP[l - 1]
                 << " ";
        }
    }
}
  
// Driver Code
int main()
{
    int arr[] = { 2, 4, 5, 6, 9 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int Q = 3;
    vector > Query
        = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
    OddDivisorsSum(N, Q, arr, Query);
  
    return 0;
}


输出:
4 4 13

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

高效方法:为了优化上述方法,其思想是使用辅助数组来存储具有奇数个除数的元素的前缀和。请按照以下步骤解决问题:

  • 使用0初始化大小为N的数组dp []
  • 使用变量i遍历给定的数组arr []并检查是否有任何元素是理想的正方形。如果发现为真,则将dp [i]的值更新为arr [i]
  • 找到数组dp []的前缀和。
  • 遍历所有查询,对于[L,R]范围内的每个查询,答案将由(dp [R] – dp [L – 1])给出

下面是上述方法的实现:

C++

// C++ program for the above approach
  
#include 
using namespace std;
  
// Function to find the sum of elements
// having odd number of divisors in
// index range [L, R] for Q queries
void OddDivisorsSum(int n, int q, int a[],
                    vector > Query)
{
    // Initialize the dp[] array
    int DP[n] = { 0 };
  
    // Traverse the array, arr[]
    for (int i = 0; i < n; i++) {
        int x = sqrt(a[i]);
  
        // If a[i] is a perfect square,
        // then update value of DP[i] to a[i]
        if (x * x == a[i])
            DP[i] = a[i];
    }
  
    // Find the prefix sum of DP[] array
    for (int i = 1; i < n; i++) {
        DP[i] = DP[i - 1] + DP[i];
    }
  
    // Iterate through all the queries
    for (int i = 0; i < q; i++) {
  
        int l = Query[i].first;
        int r = Query[i].second;
  
        // Find the sum for each query
        if (l == 0) {
            cout << DP[r] << " ";
        }
        else {
            cout << DP[r] - DP[l - 1]
                 << " ";
        }
    }
}
  
// Driver Code
int main()
{
    int arr[] = { 2, 4, 5, 6, 9 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int Q = 3;
    vector > Query
        = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
    OddDivisorsSum(N, Q, arr, Query);
  
    return 0;
}
输出:
4 4 13

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