📌  相关文章
📜  Q 查询的给定数组中 [L, R] 范围内的素数总和

📅  最后修改于: 2021-09-22 10:08:19             🧑  作者: Mango

给定一个大小为N数组 arr[]后跟一个Q 查询数组,有以下两种类型:

  • 查询类型 1:给定两个整数 L 和 R,找到从索引 L 到 R 的素数元素之和,其中 0 <= L <= R <= N-1。
  • 查询类型 2:给定两个整数 i 和 X,更改 arr[i] = X 其中 0 <= i <= n-1。

注意:子查询的每个第一个索引决定了要回答的查询类型。

例子:

朴素的方法:这个想法是对 L 到 R 之间的每个查询进行迭代,并对给定的数组执行所需的操作。

时间复杂度: O(Q * N * (O(sqrt(max(arr[i])))

方法:使用 Segment tree 和 Sieve Of Eratosthenes 来优化问题。

  • 首先,创建一个布尔数组来标记素数。
  • 现在,在制作线段树时,只将那些数组元素添加为素数的叶节点。
C++
// C++ program for the above approach
#include 
using namespace std;
 
int const MAX = 1000001;
bool prime[MAX];
 
// Function to find the prime numbers
void SieveOfEratosthenes()
{
    // Create a boolean array prime[]
    // and initialize all entries it as true
    // A value in prime[i] will
    // finally be false if i is Not a prime
    memset(prime, true, sizeof(prime));
 
    for (int p = 2; p * p <= MAX; p++) {
 
        // Check if prime[p] is not
        // changed, then it is a prime
        if (prime[p] == true) {
 
            // Update all multiples of p
            // greater than or equal to
            // the square of it numbers
            // which are multiple of p
            // and are less than p^2 are
            // already been marked
            for (int i = p * p; i <= MAX; i += p)
                prime[i] = false;
        }
    }
}
 
// Function to get the middle
// index from corner indexes
int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
// Function to get 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 with 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 update the nodes which
// have the given index in their range
void updateValueUtil(int* st, int ss,
                     int se, int i,
                     int diff, int si)
{
    // If the input index lies
    // outside the range of
    // this segment
    if (i < ss || i > se)
        return;
 
    // If the input index is in
    // range of this node, then update
    // the value of the node and its children
    st[si] = st[si] + diff;
    if (se != ss) {
        int mid = getMid(ss, se);
        updateValueUtil(st, ss, mid, i,
                        diff, 2 * si + 1);
        updateValueUtil(st, mid + 1,
                        se, i, diff,
                        2 * si + 2);
    }
}
 
// Function to update a value in
// input array and segment tree
void updateValue(int arr[], int* st,
                 int n, int i,
                 int new_val)
{
    // Check for erroneous input index
    if (i < 0 || i > n - 1) {
        cout << "-1";
        return;
    }
 
    // Get the difference between
    // new value and old value
    int diff = new_val - arr[i];
 
    int prev_val = arr[i];
 
    // Update the value in array
    arr[i] = new_val;
 
    // Update the values of
    // nodes in segment tree
    // only if either previous
    // value or new value
    // or both are prime
    if (prime[new_val]
        || prime[prev_val]) {
 
        // If only new value is prime
        if (!prime[prev_val])
            updateValueUtil(st, 0, n - 1,
                            i, new_val, 0);
 
        // If only new value is prime
        else if (!prime[new_val])
            updateValueUtil(st, 0, n - 1,
                            i, -prev_val, 0);
 
        // If both are prime
        else
            updateValueUtil(st, 0, n - 1,
                            i, diff, 0);
    }
}
 
// Return sum of elements in range
// from index qs (quey start) to qe
// (query end). It mainly uses getSumUtil()
int getSum(int* st, int n, int qs, int qe)
{
    // Check for erroneous input values
    if (qs < 0 || qe > n - 1 || qs > qe) {
        cout << "-1";
        return -1;
    }
 
    return getSumUtil(st, 0, n - 1,
                      qs, qe, 0);
}
 
// Function that constructs Segment Tree
int constructSTUtil(int arr[], int ss,
                    int se, int* st,
                    int si)
{
    // If there is one element in
    // array, store it in current node of
    // segment tree and return
    if (ss == se) {
 
        // Only add those elements in segment
        // tree which are prime
        if (prime[arr[ss]])
            st[si] = arr[ss];
        else
            st[si] = 0;
        return st[si];
    }
 
    // If there are more than one
    // elements, then recur for left and
    // right subtrees and store the
    // sum of values in this node
    int mid = getMid(ss, se);
    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 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;
}
 
// Driver code
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 11 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    int Q[3][3]
        = { { 1, 1, 3 },
            { 2, 1, 10 },
            { 1, 1, 3 } };
 
    // Function call
    SieveOfEratosthenes();
 
    // Build segment tree from given array
    int* st = constructST(arr, n);
 
    // Print sum of values in
    // array from index 1 to 3
    cout << getSum(st, n, 1, 3) << endl;
 
    // Update: set arr[1] = 10
    // and update corresponding
    // segment tree nodes
    updateValue(arr, st, n, 1, 10);
 
    // Find sum after the value is updated
    cout << getSum(st, n, 1, 3) << endl;
    return 0;
}


Java
// Java program for the above approach
import java.io.*;
import java.util.*;
class GFG
{
 
  static int MAX = 1000001;
  static int prime[] = new int[MAX];
 
  // Function to find the prime numbers
  static void SieveOfEratosthenes()
  {
 
    // Create a boolean array prime[]
    // and initialize all entries it as true
    // A value in prime[i] will
    // finally be false if i is Not a prime
    Arrays.fill(prime, 1);
 
    for (int p = 2; p * p <= MAX; p++)
    {
 
      // Check if prime[p] is not
      // changed, then it is a prime
      if (prime[p] == 1)
      {
 
        // Update all multiples of p
        // greater than or equal to
        // the square of it numbers
        // which are multiple of p
        // and are less than p^2 are
        // already been marked
        for (int i = p * p; i <= MAX - 1; i += p)
          prime[i] = 0;
      }
    }
  }
 
  // Function to get the middle
  // index from corner indexes
  static int getMid(int s, int e)
  {
    return s + (e - s) / 2;
  }
 
  // Function to get the sum of
  // values in the given range
  // of the array
  static 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 with 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 update the nodes which
  // have the given index in their range
  static void updateValueUtil(int[] st, int ss,
                              int se, int i,
                              int diff, int si)
  {
 
    // If the input index lies
    // outside the range of
    // this segment
    if (i < ss || i > se)
      return;
 
    // If the input index is in
    // range of this node, then update
    // the value of the node and its children
    st[si] = st[si] + diff;
    if (se != ss)
    {
      int mid = getMid(ss, se);
      updateValueUtil(st, ss, mid, i,
                      diff, 2 * si + 1);
      updateValueUtil(st, mid + 1,
                      se, i, diff,
                      2 * si + 2);
    }
  }
 
  // Function to update a value in
  // input array and segment tree
  static void updateValue(int arr[], int[] st,
                          int n, int i, int new_val)
  {
 
    // Check for erroneous input index
    if (i < 0 || i > n - 1)
    {
      System.out.print("-1");
      return;
    }
 
    // Get the difference between
    // new value and old value
    int diff = new_val - arr[i];
 
    int prev_val = arr[i];
 
    // Update the value in array
    arr[i] = new_val;
 
    // Update the values of
    // nodes in segment tree
    // only if either previous
    // value or new value
    // or both are prime
    if ((prime[new_val] | prime[prev_val]) != 0)
    {
 
      // If only new value is prime
      if (prime[prev_val] == 0)
        updateValueUtil(st, 0, n - 1,
                        i, new_val, 0);
 
      // If only new value is prime
      else if (prime[new_val] == 0)
        updateValueUtil(st, 0, n - 1, i, -prev_val, 0);
 
      // If both are prime
      else
        updateValueUtil(st, 0, n - 1,
                        i, diff, 0);
    }
  }
 
  // Return sum of elements in range
  // from index qs (quey start) to qe
  // (query end). It mainly uses getSumUtil()
  static int getSum(int[] st, int n, int qs, int qe)
  {
 
    // Check for erroneous input values
    if (qs < 0 || qe > n - 1 || qs > qe)
    {
      System.out.println( "-1");
      return -1;
    }
 
    return getSumUtil(st, 0, n - 1,
                      qs, qe, 0);
  }
 
  // Function that constructs Segment Tree
  static int constructSTUtil(int arr[], int ss,
                             int se, int[] st, int si)
  {
    // If there is one element in
    // array, store it in current node of
    // segment tree and return
    if (ss == se) {
 
      // Only add those elements in segment
      // tree which are prime
      if (prime[arr[ss]] != 0)
        st[si] = arr[ss];
      else
        st[si] = 0;
      return st[si];
    }
 
    // If there are more than one
    // elements, then recur for left and
    // right subtrees and store the
    // sum of values in this node
    int mid = getMid(ss, se);
    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 given array
  static int[] constructST(int arr[], int n)
  {
    // Allocate memory for the segment tree
 
    // Height of segment tree
    int x = (int)(Math.ceil(Math.log(n)/Math.log(2)));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)Math.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;
  }
 
  // Driver Code
  public static void main(String[] args)
  {
    int arr[] = { 1, 3, 5, 7, 9, 11 };
    int n = arr.length;
 
    int Q[][] = { { 1, 1, 3 },
                 { 2, 1, 10 },
                 { 1, 1, 3 } };
 
    // Function call
    SieveOfEratosthenes();
 
    // Build segment tree from given array
    int[] st = constructST(arr, n);
 
    // Print sum of values in
    // array from index 1 to 3
    System.out.println(getSum(st, n, 1, 3));
 
    // Update: set arr[1] = 10
    // and update corresponding
    // segment tree nodes
    updateValue(arr, st, n, 1, 10);
 
    // Find sum after the value is updated
    System.out.println(getSum(st, n, 1, 3));
  }
}
 
// This coe is contributed by susmitakundugoaldanga


Python3
# Python3 program for the above approach
import math
MAX = 1000001
 
# Create a boolean array prime[]
# and initialize all entires it as true
# A value in prime[i] will
# finally be false if i is Not a prime
prime = [True] * MAX
 
# Function to find prime numbers
def SieveOfEratosthenes():
     
    p = 2
    while p * p <= MAX:
         
        # Check if prime[p] is not
        # changed, then it is a prime
        if prime[p] == True:
             
            # Update all multiples of p
            # greater than or equal to
            # the square of it numbers
            # which are multiple of p
            # and are less than p^2 are
            # already been marked
            for i in range(p * p, MAX, p):
                prime[i] = False
         
        p += 1
         
# Function to get the middle
# index from corner indexes
def getMid(s, e):
     
    return s + (e - s) // 2
 
# Function to get the sum of
# values in the given range
# of the array
def getSumUtil(st, ss, se, qs, qe, si):
     
    # If segment of this node is a
    # part of given range, then
    # return the sum of the segment
    if qs <= ss and qe >= se:
        return st[si]
     
    # If segment of this node is
    # outside the given range
    if se < qs or ss > qe:
        return 0
     
    # If a part of this segment
    # overlaps with the given range
    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 update the nodes which
# have the given index in their range
def updateValueUtil(st, ss, se, i, diff, si):
     
    # If the input index lies
    # outside the range of
    # this segment
    if i < ss or i > se:
        return
     
    # If the input index is in
    # range of this node, then update
    # the value of the node and its children
    st[si] = st[si] + diff
     
    if se != ss:
        mid = getMid(ss, se)
        updateValueUtil(st, ss, mid, i,
                        diff, 2 * si + 1)
        updateValueUtil(st, mid + 1, se, i,
                        diff, 2 * si + 2)
         
# Function to update a value in
# input array and segment tree
def updateValue(arr, st, n, i, new_val):
     
    # Check for errorneous imput index
    if i < 0 or i > n - 1:
        print(-1)
        return
     
    # Get the difference between
    # new value and old value
    diff = new_val - arr[i]
     
    prev_val = arr[i]
     
    # Update the value in array
    arr[i] = new_val
     
    # Update the values of nodes
    # in segment tree only if
    # either previous value or
    # new value or both are prime
    if prime[new_val] or prime[prev_val]:
         
        # If only new value is prime
        if not prime[prev_val]:
            updateValueUtil(st, 0, n - 1,
                            i, new_val, 0)
         
        # If only old value is prime
        elif not prime[new_val]:
            updateValueUtil(st, 0, n - 1, i,
                            -prev_val, 0)
         
        # If both are prime
        else:
            updateValueUtil(st, 0, n - 1,
                            i, diff, 0)
             
# Return sum of elements in range
# from index qs (quey start) to qe
# (query end). It mainly uses getSumUtil()
def getSum(st, n, qs, qe):
     
    # Check for erroneous input values
    if qs < 0 or qe > n-1 or qs > qe:
        return -1
     
    return getSumUtil(st, 0, n - 1, qs, qe, 0)
 
# Function that constructs the Segment Tree
def constructSTUtil(arr, ss, se, st, si):
     
    # If there is one element in
    # array, store it in current 
    # node of segment tree and return
    if ss == se:
         
        # Only add those elements in segment
        # tree which are prime
        if prime[arr[ss]]:
            st[si] = arr[ss]
        else:
            st[si] = 0
         
        return st[si]
     
    # If there are more than one
    # elements, then recur for left and
    # right subtrees and store the
    # sum of values in this node
    mid = getMid(ss, se)
    st[si] = (constructSTUtil(arr, ss, mid, st,
                              2 * si + 1) +
              constructSTUtil(arr, mid + 1, se,
                              st, 2 * si + 2))
    return st[si]
 
# Function to construct segment
# tree from given array
def constructST(arr, n):
     
    # Allocate memory for the segment tree
     
    # Height of segment tree
    x = int(math.ceil(math.log2(n)))
     
    # Maximum size of segment tree
    max_size = 2 * int(pow(2, x)) - 1
     
    # Allocate memory
    st = [0] * max_size
     
    # Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0)
     
    # Return the constructed segment tree
    return st
 
# Driver code
arr = [ 1, 3, 5, 7, 9, 11 ]
n = len(arr)
 
Q = [ [ 1, 1, 3 ],
      [ 2, 1, 10 ],
      [ 1, 1, 3 ] ]
 
# Function call
SieveOfEratosthenes()
 
# Build segment tree from given array
st = constructST(arr, n)
 
# Print sum of values in
# array from index 1 to 3
print(getSum(st, n, 1, 3))
 
# Update: set arr[1] = 10
# and update corresponding
# segment tree nodes
updateValue(arr, st, n, 1, 10)
 
# Find sum after value is updated
print(getSum(st, n, 1, 3))
 
# This code is contrinuted by Stuti Pathak


C#
// C# program for the above approach
using System;
class GFG {
     
  static int MAX = 1000001;
  static int[] prime = new int[MAX];
  
  // Function to find the prime numbers
  static void SieveOfEratosthenes()
  {
  
    // Create a boolean array prime[]
    // and initialize all entries it as true
    // A value in prime[i] will
    // finally be false if i is Not a prime
    Array.Fill(prime, 1);
  
    for (int p = 2; p * p <= MAX; p++)
    {
  
      // Check if prime[p] is not
      // changed, then it is a prime
      if (prime[p] == 1)
      {
  
        // Update all multiples of p
        // greater than or equal to
        // the square of it numbers
        // which are multiple of p
        // and are less than p^2 are
        // already been marked
        for (int i = p * p; i <= MAX - 1; i += p)
          prime[i] = 0;
      }
    }
  }
  
  // Function to get the middle
  // index from corner indexes
  static int getMid(int s, int e)
  {
    return s + (e - s) / 2;
  }
  
  // Function to get the sum of
  // values in the given range
  // of the array
  static 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 with 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 update the nodes which
  // have the given index in their range
  static void updateValueUtil(int[] st, int ss,
                              int se, int i,
                              int diff, int si)
  {
  
    // If the input index lies
    // outside the range of
    // this segment
    if (i < ss || i > se)
      return;
  
    // If the input index is in
    // range of this node, then update
    // the value of the node and its children
    st[si] = st[si] + diff;
    if (se != ss)
    {
      int mid = getMid(ss, se);
      updateValueUtil(st, ss, mid, i,
                      diff, 2 * si + 1);
      updateValueUtil(st, mid + 1,
                      se, i, diff,
                      2 * si + 2);
    }
  }
  
  // Function to update a value in
  // input array and segment tree
  static void updateValue(int[] arr, int[] st,
                          int n, int i, int new_val)
  {
  
    // Check for erroneous input index
    if (i < 0 || i > n - 1)
    {
      Console.Write("-1");
      return;
    }
  
    // Get the difference between
    // new value and old value
    int diff = new_val - arr[i];
  
    int prev_val = arr[i];
  
    // Update the value in array
    arr[i] = new_val;
  
    // Update the values of
    // nodes in segment tree
    // only if either previous
    // value or new value
    // or both are prime
    if ((prime[new_val] | prime[prev_val]) != 0)
    {
  
      // If only new value is prime
      if (prime[prev_val] == 0)
        updateValueUtil(st, 0, n - 1,
                        i, new_val, 0);
  
      // If only new value is prime
      else if (prime[new_val] == 0)
        updateValueUtil(st, 0, n - 1, i, -prev_val, 0);
  
      // If both are prime
      else
        updateValueUtil(st, 0, n - 1,
                        i, diff, 0);
    }
  }
  
  // Return sum of elements in range
  // from index qs (quey start) to qe
  // (query end). It mainly uses getSumUtil()
  static int getSum(int[] st, int n, int qs, int qe)
  {
  
    // Check for erroneous input values
    if (qs < 0 || qe > n - 1 || qs > qe)
    {
      Console.WriteLine( "-1");
      return -1;
    }
  
    return getSumUtil(st, 0, n - 1,
                      qs, qe, 0);
  }
  
  // Function that constructs Segment Tree
  static int constructSTUtil(int[] arr, int ss,
                             int se, int[] st, int si)
  {
     
    // If there is one element in
    // array, store it in current node of
    // segment tree and return
    if (ss == se) {
  
      // Only add those elements in segment
      // tree which are prime
      if (prime[arr[ss]] != 0)
        st[si] = arr[ss];
      else
        st[si] = 0;
      return st[si];
    }
  
    // If there are more than one
    // elements, then recur for left and
    // right subtrees and store the
    // sum of values in this node
    int mid = getMid(ss, se);
    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 given array
  static int[] constructST(int[] arr, int n)
  {
     
    // Allocate memory for the segment tree
  
    // Height of segment tree
    int x = (int)(Math.Ceiling(Math.Log(n,2)));
  
    // Maximum size of segment tree
    int max_size = 2 * (int)Math.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;
  }
   
  // Driver code
  static void Main()
  {
    int[] arr = { 1, 3, 5, 7, 9, 11 };
    int n = arr.Length;
  
    // Function call
    SieveOfEratosthenes();
  
    // Build segment tree from given array
    int[] st = constructST(arr, n);
  
    // Print sum of values in
    // array from index 1 to 3
    Console.WriteLine(getSum(st, n, 1, 3));
  
    // Update: set arr[1] = 10
    // and update corresponding
    // segment tree nodes
    updateValue(arr, st, n, 1, 10);
  
    // Find sum after the value is updated
    Console.WriteLine(getSum(st, n, 1, 3));
  }
}
 
// This code is contributed by divyesh072019.


Javascript


输出:
15
12

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

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程