📜  子数组中的素数(带有更新)

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

给定一个由N个整数组成的数组,任务是执行以下两个查询:

例子:

Input : arr = {1, 2, 3, 5, 7, 9}
        Query 1: query(start = 0, end = 4)
        Query 2: update(i = 3, x = 6)
        Query 3: query(start = 0, end = 4)
Output :4
        3
Explanation
In Query 1, the subarray [0...4]
has 4 primes viz. {2, 3, 5, 7}

In Query 2, the value at index 3 
is updated to 6, the array arr now is, {1, 2, 3, 
6, 7, 9}
In Query 3, the subarray [0...4]
has 4 primes viz. {2, 3, 7}

方法1(蛮力)
在这里可以找到类似的问题。这里没有更新,我们可以对其进行修改以处理更新,但是为此,我们在执行更新时始终需要构建前缀数组,这使得该方法的时间复杂度为O(Q * N)
方法2(高效)
由于我们需要处理范围查询和点更新,因此分段树最适合此目的。
我们可以使用埃拉托色尼的筛分预处理所有的素数,直到改编可以说MAX在O最大值(MAX日志(LOG(MAX)))
构建段树:
我们基本上使用分段树将问题简化为子数组总和。
现在,我们可以构建段树,其中叶节点表示为0(如果不是素数)或1(如果是素数)。
段树的内部节点等于其子节点的总和,因此,一个节点表示从L到R的范围内的总素数,其中L到R的范围落在该节点之下,而子树在其下方。
处理查询和积分更新:
每当我们从头到尾进行查询时,我们都可以查询段树以查找范围从头到尾的节点总数,这又表示范围从头到尾的素数。
如果需要执行点更新并将索引i处的值更新为x,则我们检查以下情况:

Let the old value of arri be y and the new value be x

Case 1: If x and y both are primes
Count of primes in the subarray does not change so we just update array and donot
modify the segment tree

Case 2: If x and y both are non primes
Count of primes in the subarray does not change so we just update array and donot
modify the segment tree

Case 3: If y is prime but x is non prime
Count of primes in the subarray decreases so we update array and add -1 to every 
range, the index i which is to be updated, is a part of in the segment tree

Case 4: If y is non prime but x is prime
Count of primes in the subarray increases so we update array and add 1 to every 
range, the index i which is to be updated, is a part of in the segment tree
CPP
// C++ program to find number of prime numbers in a
// subarray and performing updates
#include 
using namespace std;
 
#define MAX 1000
 
void sieveOfEratosthenes(bool isPrime[])
{
    isPrime[1] = false;
 
    for (int p = 2; p * p <= MAX; p++) {
 
        // If prime[p] is not changed, then
        // it is a prime
        if (isPrime[p] == true) {
 
            // Update all multiples of p
            for (int i = p * 2; i <= MAX; i += p)
                isPrime[i] = false;
        }
    }
}
 
// A utility function to get the middle index from corner indexes.
int getMid(int s, int e) { return s + (e - s) / 2; }
 
/*  A recursive function to get the number of primes in a given range
     of array indexes. The following are parameters for this function.
  
    st    --> Pointer to segment tree
    index --> Index of current node in the segment tree. Initially
              0 is passed as root is always at index 0
    ss & se  --> Starting and ending indexes of the segment represented
                  by current node, i.e., st[index]
    qs & qe  --> Starting and ending indexes of query range */
int queryPrimesUtil(int* st, int ss, int se, int qs, int qe, int index)
{
    // If segment of this node is a part of given range, then return
    // the number of primes in the segment
    if (qs <= ss && qe >= se)
        return st[index];
 
    // 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 queryPrimesUtil(st, ss, mid, qs, qe, 2 * index + 1) +
           queryPrimesUtil(st, mid + 1, se, qs, qe, 2 * index + 2);
}
 
/* A recursive function to update the nodes which have the given
   index in their range. The following are parameters
    st, si, ss and se are same as getSumUtil()
    i    --> index of the element to be updated. This index is
             in input array.
   diff --> Value to be added to all nodes which have i in range */
void updateValueUtil(int* st, int ss, int se, int i, int diff, int si)
{
    // Base Case: 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);
    }
}
 
// The function to update a value in input array and segment tree.
// It uses updateValueUtil() to update the value in segment tree
void updateValue(int arr[], int* st, int n, int i, int new_val,
                                               bool isPrime[])
{
    // Check for erroneous input index
    if (i < 0 || i > n - 1) {
        printf("Invalid Input");
        return;
    }
 
    int diff, oldValue;
 
    oldValue = arr[i];
 
    // Update the value in array
    arr[i] = new_val;
 
    // Case 1: Old and new values both are primes
    if (isPrime[oldValue] && isPrime[new_val])
        return;
 
    // Case 2: Old and new values both non primes
    if ((!isPrime[oldValue]) && (!isPrime[new_val]))
        return;
 
    // Case 3: Old value was prime, new value is non prime
    if (isPrime[oldValue] && !isPrime[new_val]) {
        diff = -1;
    }
 
    // Case 4: Old value was non prime, new_val is prime
    if (!isPrime[oldValue] && isPrime[new_val]) {
        diff = 1;
    }
 
    // Update the values of nodes in segment tree
    updateValueUtil(st, 0, n - 1, i, diff, 0);
}
 
// Return number of primes in range from index qs (query start) to
// qe (query end).  It mainly uses queryPrimesUtil()
void queryPrimes(int* st, int n, int qs, int qe)
{
    int primesInRange = queryPrimesUtil(st, 0, n - 1, qs, qe, 0);
 
    cout << "Number of Primes in subarray from " << qs << " to "
         << qe << " = " << primesInRange << "\n";
}
 
// A recursive function that constructs Segment Tree
// for array[ss..se].
// si is index of current node in segment tree st
int constructSTUtil(int arr[], int ss, int se, int* st,
                                 int si, bool isPrime[])
{
    // If there is one element in array, check if it
    // is prime then store 1 in the segment tree else
    // store 0 and return
    if (ss == se) {
 
        // if arr[ss] is prime
        if (isPrime[arr[ss]])
            st[si] = 1;       
        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 the two values in this node
    int mid = getMid(ss, se);
    st[si] = constructSTUtil(arr, ss, mid, st,
                               si * 2 + 1, isPrime) +
             constructSTUtil(arr, mid + 1, se, st,
                              si * 2 + 2, isPrime);
    return st[si];
}
 
/* Function to construct segment tree from given array.
   This function allocates memory for segment tree and
   calls constructSTUtil() to fill the allocated memory */
int* constructST(int arr[], int n, bool isPrime[])
{
    // Allocate memory for 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;
 
    int* st = new int[max_size];
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0, isPrime);
 
    // Return the constructed segment tree
    return st;
}
 
// Driver program to test above functions
int main()
{
 
    int arr[] = { 1, 2, 3, 5, 7, 9 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    /* Preprocess all primes till MAX.
       Create a boolean array "isPrime[0..MAX]".
       A value in prime[i] will finally be false
       if i is Not a prime, else true. */
 
    bool isPrime[MAX + 1];
    memset(isPrime, true, sizeof isPrime);
    sieveOfEratosthenes(isPrime);
 
    // Build segment tree from given array
    int* st = constructST(arr, n, isPrime);
 
    // Query 1: Query(start = 0, end = 4)
    int start = 0;
    int end = 4;
    queryPrimes(st, n, start, end);
 
    // Query 2: Update(i = 3, x = 6), i.e Update
    // a[i] to x
    int i = 3;
    int x = 6;
    updateValue(arr, st, n, i, x, isPrime);
 
    // uncomment to see array after update
    // for(int i = 0; i < n; i++) cout << arr[i] << " ";
 
    // Query 3: Query(start = 0, end = 4)
    start = 0;
    end = 4;
    queryPrimes(st, n, start, end);
 
    return 0;
}


Java
// Java program to find number of prime numbers in a 
// subarray and performing updates
import java.io.*;
import java.util.*;
 
class GFG
{
    static int MAX = 1000 ;
    static void sieveOfEratosthenes(boolean isPrime[])
    {
        isPrime[1] = false;
        for (int p = 2; p * p <= MAX; p++)
        {
   
            // If prime[p] is not changed, then
            // it is a prime
            if (isPrime[p] == true)
            {
   
                // Update all multiples of p
                for (int i = p * 2; i <= MAX; i += p)
                    isPrime[i] = false;
            }
        }
    }
     
    // A utility function to get the middle index from corner indexes.
    static int getMid(int s, int e) { return s + (e - s) / 2; }
     
    /*  A recursive function to get the number of primes in a given range
     of array indexes. The following are parameters for this function.
    
    st    --> Pointer to segment tree
    index --> Index of current node in the segment tree. Initially
              0 is passed as root is always at index 0
    ss & se  --> Starting and ending indexes of the segment represented
                  by current node, i.e., st[index]
    qs & qe  --> Starting and ending indexes of query range */
     
    static int queryPrimesUtil(int[] st, int ss, int se, int qs, int qe, int index)
    {
       
        // If segment of this node is a part of given range, then return
        // the number of primes in the segment      
        if (qs <= ss && qe >= se)
        return st[index];
   
        // 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 queryPrimesUtil(st, ss, mid, qs, qe, 2 * index + 1) +
          queryPrimesUtil(st, mid + 1, se, qs, qe, 2 * index + 2);
    }
     
    /* A recursive function to update the nodes which have the given 
   index in their range. The following are parameters
    st, si, ss and se are same as getSumUtil()
    i    --> index of the element to be updated. This index is 
             in input array.
   diff --> Value to be added to all nodes which have i in range */
    
   static void updateValueUtil(int[] st, int ss, int se, int i, int diff, int si)
   {
        // Base Case: 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);
        }
    }
     
    // The function to update a value in input array and segment tree.
    // It uses updateValueUtil() to update the value in segment tree
     
    static void updateValue(int arr[], int[] st, int n,
                            int i, int new_val, boolean isPrime[])
    {
        // Check for erroneous input index
        if (i < 0 || i > n - 1) {
            System.out.println("Invalid Input");
            return;
        }
        int diff = 0;
        int oldValue;
   
        oldValue = arr[i];
   
        // Update the value in array
        arr[i] = new_val;
   
        // Case 1: Old and new values both are primes
        if (isPrime[oldValue] && isPrime[new_val])
            return;
   
        // Case 2: Old and new values both non primes
        if ((!isPrime[oldValue]) && (!isPrime[new_val]))
            return;
   
        // Case 3: Old value was prime, new value is non prime
        if (isPrime[oldValue] && !isPrime[new_val])
        {
            diff = -1;
        }
   
        // Case 4: Old value was non prime, new_val is prime
        if (!isPrime[oldValue] && isPrime[new_val])
        {
            diff = 1;
        }
   
        // Update the values of nodes in segment tree
        updateValueUtil(st, 0, n - 1, i, diff, 0);
    }
     
    // Return number of primes in range from index qs (query start) to
    // qe (query end).  It mainly uses queryPrimesUtil()
    static void queryPrimes(int[] st, int n, int qs, int qe)
    {
        int primesInRange = queryPrimesUtil(st, 0, n - 1, qs, qe, 0);
        System.out.println("Number of Primes in subarray from " +
                           qs + " to " + qe + " = " + primesInRange);
    }
 
    // A recursive function that constructs Segment Tree 
    // for array[ss..se].
    // si is index of current node in segment tree st
    static int constructSTUtil(int arr[], int ss, int se,
                               int[] st, int si, boolean isPrime[])
    {
        // If there is one element in array, check if it
        // is prime then store 1 in the segment tree else
        // store 0 and return
        if (ss == se) {
   
            // if arr[ss] is prime
            if (isPrime[arr[ss]]) 
                st[si] = 1;        
            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 the two values in this node
        int mid = getMid(ss, se);
        st[si] = constructSTUtil(arr, ss, mid, st, si * 2 + 1, isPrime) + 
                constructSTUtil(arr, mid + 1, se, st, si * 2 + 2, isPrime);
        return st[si];
    }
         
    /* Function to construct segment tree from given array. 
   This function allocates memory for segment tree and
   calls constructSTUtil() to fill the allocated memory */
   static int[] constructST(int arr[], int n, boolean isPrime[])
   {
       // Allocate memory for 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;  
        int[] st = new int[max_size];
   
        // Fill the allocated memory st
        constructSTUtil(arr, 0, n - 1, st, 0, isPrime);
   
        // Return the constructed segment tree
        return st;
   }
     
  // Driver code
    public static void main (String[] args)
    {
        int arr[] = { 1, 2, 3, 5, 7, 9 };
        int n = arr.length;
       
        /* Preprocess all primes till MAX.
       Create a boolean array "isPrime[0..MAX]".
       A value in prime[i] will finally be false 
       if i is Not a prime, else true. */
        boolean[] isPrime = new boolean[MAX + 1];
        Arrays.fill(isPrime, Boolean.TRUE);
        sieveOfEratosthenes(isPrime);
        
        // Build segment tree from given array
        int[] st = constructST(arr, n, isPrime);
   
        // Query 1: Query(start = 0, end = 4)
        int start = 0;
        int end = 4;
        queryPrimes(st, n, start, end);
   
        // Query 2: Update(i = 3, x = 6), i.e Update 
        // a[i] to x
        int i = 3;
        int x = 6;
        updateValue(arr, st, n, i, x, isPrime);
   
        // uncomment to see array after update
        // for(int i = 0; i < n; i++) cout << arr[i] << " ";
   
        // Query 3: Query(start = 0, end = 4)
        start = 0;
        end = 4;
        queryPrimes(st, n, start, end);
    }
}
 
// This code is contributed by avanitrachhadiya2155


Python3
# Python3 program to find number of prime numbers in a
# subarray and performing updates
from math import ceil, floor, log
MAX = 1000
 
def sieveOfEratosthenes(isPrime):
 
    isPrime[1] = False
 
    for p in range(2, MAX + 1):
        if p  * p > MAX:
            break
 
        # If prime[p] is not changed, then
        # it is a prime
        if (isPrime[p] == True):
 
            # Update all multiples of p
            for i in range(2 * p, MAX + 1, p):
                isPrime[i] = False
 
# A utility function to get the middle index from corner indexes.
def getMid(s, e):
    return s + (e - s) // 2
#
# /* A recursive function to get the number of primes in a given range
#     of array indexes. The following are parameters for this function.
#
#     st --> Pointer to segment tree
#     index --> Index of current node in the segment tree. Initially
#             0 is passed as root is always at index 0
#     ss & se --> Starting and ending indexes of the segment represented
#                 by current node, i.e., st[index]
#     qs & qe --> Starting and ending indexes of query range */
def queryPrimesUtil(st, ss, se, qs, qe, index):
 
    # If segment of this node is a part of given range, then return
    # the number of primes in the segment
    if (qs <= ss and qe >= se):
        return st[index]
 
    # 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 queryPrimesUtil(st, ss, mid, qs, qe, 2 * index + 1) + \
            queryPrimesUtil(st, mid + 1, se, qs, qe, 2 * index + 2)
 
# /* A recursive function to update the nodes which have the given
# index in their range. The following are parameters
#     st, si, ss and se are same as getSumUtil()
#     i --> index of the element to be updated. This index is
#             in input array.
# diff --> Value to be added to all nodes which have i in range */
def updateValueUtil(st, ss, se, i, diff, si):
 
    # Base Case: 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)
 
# The function to update a value in input array and segment tree.
# It uses updateValueUtil() to update the value in segment tree
def updateValue(arr,st, n, i, new_val,isPrime):
 
    # Check for erroneous input index
    if (i < 0 or i > n - 1):
        printf("Invalid Input")
        return
 
    diff, oldValue = 0, 0
 
    oldValue = arr[i]
 
    # Update the value in array
    arr[i] = new_val
 
    # Case 1: Old and new values both are primes
    if (isPrime[oldValue] and isPrime[new_val]):
        return
 
    # Case 2: Old and new values both non primes
    if ((not isPrime[oldValue]) and (not isPrime[new_val])):
        return
 
    # Case 3: Old value was prime, new value is non prime
    if (isPrime[oldValue] and not isPrime[new_val]):
        diff = -1
 
    # Case 4: Old value was non prime, new_val is prime
    if (not isPrime[oldValue] and isPrime[new_val]):
        diff = 1
 
    # Update the values of nodes in segment tree
    updateValueUtil(st, 0, n - 1, i, diff, 0)
 
# Return number of primes in range from index qs (query start) to
# qe (query end). It mainly uses queryPrimesUtil()
def queryPrimes(st, n, qs, qe):
 
    primesInRange = queryPrimesUtil(st, 0, n - 1, qs, qe, 0)
 
    print("Number of Primes in subarray from ", qs," to ", qe," = ", primesInRange)
 
# A recursive function that constructs Segment Tree
# for array[ss..se].
# si is index of current node in segment tree st
def constructSTUtil(arr, ss, se, st,si,isPrime):
 
    # If there is one element in array, check if it
    # is prime then store 1 in the segment tree else
    # store 0 and return
    if (ss == se):
 
        # if arr[ss] is prime
        if (isPrime[arr[ss]]):
            st[si] = 1
        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 the two values in this node
    mid = getMid(ss, se)
    st[si] = constructSTUtil(arr, ss, mid, st,si * 2 + 1, isPrime) + \
            constructSTUtil(arr, mid + 1, se, st,si * 2 + 2, isPrime)
    return st[si]
 
# /* Function to construct segment tree from given array.
# This function allocates memory for segment tree and
# calls constructSTUtil() to fill the allocated memory */
def constructST(arr, n, isPrime):
 
    # Allocate memory for segment tree
 
    # Height of segment tree
    x = ceil(log(n, 2))
 
    # Maximum size of segment tree
    max_size = 2 * pow(2, x) - 1
 
    st = [0]*(max_size)
 
    # Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0, isPrime)
 
    # Return the constructed segment tree
    return st
 
# Driver code
if __name__ == '__main__':
 
    arr= [ 1, 2, 3, 5, 7, 9]
    n = len(arr)
 
    # /* Preprocess all primes till MAX.
    # Create a boolean array "isPrime[0..MAX]".
    # A value in prime[i] will finally be false
    # if i is Not a prime, else true. */
 
    isPrime = [True]*(MAX + 1)
    sieveOfEratosthenes(isPrime)
 
    # Build segment tree from given array
    st = constructST(arr, n, isPrime)
 
    # Query 1: Query(start = 0, end = 4)
    start = 0
    end = 4
    queryPrimes(st, n, start, end)
 
    # Query 2: Update(i = 3, x = 6), i.e Update
    # a[i] to x
    i = 3
    x = 6
    updateValue(arr, st, n, i, x, isPrime)
 
    # uncomment to see array after update
    # for(i = 0 i < n i++) cout << arr[i] << " "
 
    # Query 3: Query(start = 0, end = 4)
    start = 0
    end = 4
    queryPrimes(st, n, start, end)
 
# This code is contributed by mohit kumar 29


C#
// C# program to find number of prime numbers in a 
// subarray and performing updates
using System;
public class GFG
{
  static int MAX = 1000 ;
  static void sieveOfEratosthenes(bool[] isPrime)
  {
    isPrime[1] = false;
    for (int p = 2; p * p <= MAX; p++)
    {
 
      // If prime[p] is not changed, then
      // it is a prime
      if (isPrime[p] == true)
      {
 
        // Update all multiples of p
        for (int i = p * 2; i <= MAX; i += p)
          isPrime[i] = false;
      }
    }
  }
 
  // A utility function to get the middle index from corner indexes.
  static int getMid(int s, int e)
  {
    return s + (e - s) / 2;
  }
 
  /*  A recursive function to get the number of primes in a given range
     of array indexes. The following are parameters for this function.
 
    st    --> Pointer to segment tree
    index --> Index of current node in the segment tree. Initially
              0 is passed as root is always at index 0
    ss & se  --> Starting and ending indexes of the segment represented
                  by current node, i.e., st[index]
    qs & qe  --> Starting and ending indexes of query range */
  static int queryPrimesUtil(int[] st, int ss, int se,
                             int qs, int qe, int index)
  {
 
    // If segment of this node is a part of given range, then return
    // the number of primes in the segment      
    if (qs <= ss && qe >= se)
      return st[index];
 
    // 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 queryPrimesUtil(st, ss, mid, qs,
                           qe, 2 * index + 1) +
      queryPrimesUtil(st, mid + 1, se,
                      qs, qe, 2 * index + 2);
  }
 
  /* A recursive function to update the nodes which have the given 
   index in their range. The following are parameters
    st, si, ss and se are same as getSumUtil()
    i    --> index of the element to be updated. This index is 
             in input array.
   diff --> Value to be added to all nodes which have i in range */
  static void updateValueUtil(int[] st, int ss, int se,
                              int i, int diff, int si)
  {
 
    // Base Case: 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);
    }
  }
 
  // The function to update a value in input array and segment tree.
  // It uses updateValueUtil() to update the value in segment tree
  static void updateValue(int[] arr, int[] st, int n,
                          int i, int new_val, bool[] isPrime)
  {
 
    // Check for erroneous input index
    if (i < 0 || i > n - 1)
    {
      Console.WriteLine("Invalid Input");
      return;
    }
    int diff = 0;
    int oldValue;
    oldValue = arr[i];
 
    // Update the value in array
    arr[i] = new_val;
 
    // Case 1: Old and new values both are primes
    if (isPrime[oldValue] && isPrime[new_val])
      return;
 
    // Case 2: Old and new values both non primes
    if ((!isPrime[oldValue]) && (!isPrime[new_val]))
      return;
 
    // Case 3: Old value was prime, new value is non prime
    if (isPrime[oldValue] && !isPrime[new_val])
    {
      diff = -1;
    }
 
    // Case 4: Old value was non prime, new_val is prime
    if (!isPrime[oldValue] && isPrime[new_val])
    {
      diff = 1;
    }
 
    // Update the values of nodes in segment tree
    updateValueUtil(st, 0, n - 1, i, diff, 0);
  }
 
  // Return number of primes in range from index qs (query start) to
  // qe (query end).  It mainly uses queryPrimesUtil()
  static void queryPrimes(int[] st, int n, int qs, int qe)
  {
    int primesInRange = queryPrimesUtil(st, 0, n - 1, qs, qe, 0);
    Console.WriteLine("Number of Primes in subarray from " +
                      qs + " to " + qe + " = " + primesInRange);
  }
 
  // A recursive function that constructs Segment Tree 
  // for array[ss..se].
  // si is index of current node in segment tree st
  static int constructSTUtil(int[] arr, int ss, int se,
                             int[] st, int si, bool[] isPrime)
  {
 
    // If there is one element in array, check if it
    // is prime then store 1 in the segment tree else
    // store 0 and return
    if (ss == se)
    {
 
      // if arr[ss] is prime
      if (isPrime[arr[ss]]) 
        st[si] = 1;        
      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 the two values in this node
    int mid = getMid(ss, se);
    st[si] = constructSTUtil(arr, ss, mid, st,
                             si * 2 + 1, isPrime) +
      constructSTUtil(arr, mid + 1, se, st, si * 2 + 2, isPrime);
    return st[si];
  }
 
  /* Function to construct segment tree from given array. 
   This function allocates memory for segment tree and
   calls constructSTUtil() to fill the allocated memory */
  static int[] constructST(int[] arr, int n, bool[] isPrime)
  {
 
    // Allocate memory for segment tree
 
    // Height of segment tree
    int x = (int)(Math.Ceiling(Math.Log(n) / Math.Log(2)));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)Math.Pow(2, x) - 1;  
    int[] st = new int[max_size];
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0, isPrime);
 
    // Return the constructed segment tree
    return st;
  }
 
  // Driver code
  static public void Main ()
  {
    int[] arr = { 1, 2, 3, 5, 7, 9 };
    int n = arr.Length;
 
    /* Preprocess all primes till MAX.
       Create a boolean array "isPrime[0..MAX]".
       A value in prime[i] will finally be false 
       if i is Not a prime, else true. */
    bool[] isPrime = new bool[MAX + 1];
    Array.Fill(isPrime, true);
    sieveOfEratosthenes(isPrime);
 
    // Build segment tree from given array
    int[] st = constructST(arr, n, isPrime);
 
    // Query 1: Query(start = 0, end = 4)
    int start = 0;
    int end = 4;
    queryPrimes(st, n, start, end);
 
    // Query 2: Update(i = 3, x = 6), i.e Update 
    // a[i] to x
    int i = 3;
    int x = 6;
    updateValue(arr, st, n, i, x, isPrime);
 
    // uncomment to see array after update
    // for(int i = 0; i < n; i++) cout << arr[i] << " ";
 
    // Query 3: Query(start = 0, end = 4)
    start = 0;
    end = 4;
    queryPrimes(st, n, start, end);
  }
}
 
// This code is contributed by rag2127


输出:
Number of Primes in subarray from 0 to 4 = 4
Number of Primes in subarray from 0 to 4 = 3

每个查询和更新的时间复杂度为O(logn),而构建段树的时间复杂度为O(n)
注意:这里,使用Eratothethenes筛子预处理到质子直到MAX的时间复杂度为O(MAX log(log(MAX))),其中MAX是可以取的最大值