📌  相关文章
📜  允许更新时计算给定数组范围内的原始数

📅  最后修改于: 2022-05-13 01:56:10.216000             🧑  作者: Mango

允许更新时计算给定数组范围内的原始数

给定一个由N个正整数组成的数组,以及Q个查询,其中每个查询是以下类型之一:

  1. 1 lr - 需要打印索引范围内的原始计数[l, r]
  2. 2 px - 需要在给定索引p处分配一个值x

例子:

朴素方法:基本方法是使用升序存储素数 筛法。然后对于第一种类型的每个查询,检查该范围内的所有元素并找到原始的计数,对于第二种类型的查询,将该值分配给给定的索引。

请按照以下步骤查找数字是否为原始数字:

  • 从存储的第一个素数开始。
  • 继续将这些存储的素数相乘。
  • 如果素数的乘积在任何时候都等于 arr[i],则 arr[i] 是一个原始的。
  • 如果乘积超过 arr[i],则 arr[i] 不是原始的。

请按照下图更好地了解如何找到原始

插图:

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

有效的方法:这个问题可以通过使用基于以下观察的段树在更短的时间内解决查询来更有效地解决:

按照以下过程实现段树数据结构。

按照下面提到的步骤来实施该方法:

  • 使用埃拉托色尼筛法标记所有素数。
  • 将原始值存储在地图中(例如primorial
  • 为索引 0 到 N-1 的数组构建段树
  • 现在对于第一种类型的每个查询,在段树中找到该范围的值,对于第二种类型,使用给定值更新段树。

下面是上述方法的实现。

C++
// C++ code to count primorials
// in the given range for Q queries
 
#include 
using namespace std;
const int mxx = 1e6 + 3;
vector isPrime(1000, true);
int segment[4 * mxx];
unordered_map primorial;
 
// Mark true all prime numbers
void sieve()
{
    isPrime[0] = isPrime[1] = false;
    for (int i = 2; i < 1000; i++) {
        if (isPrime[i]) {
            for (int j = 2 * i; j < 1000;
                 j = j + i)
                // Mark false which are the
                // multiple of prime numbers
                isPrime[j] = false;
        }
    }
}
 
// Store primorials
void store_primorials()
{
    int cnt = 0;
    long long product = 1;
    for (int i = 2; i < mxx && cnt < 15;
         i++) {
        if (isPrime[i]) {
            product = product * 1LL * i;
            primorial[product]++;
            cnt++;
        }
    }
}
 
// To build segment tree
void build(int arr[], int low, int high,
           int ind)
{
    // The node is leaf node
    if (low == high) {
        // If array value is primorial
        // assign leaf node value 1
        // otherwise 0
        auto it = primorial.find(arr[low]);
        if (it != primorial.end())
            segment[ind] = 1;
        else
            segment[ind] = 0;
        return;
    }
 
    int mid = (low + high) >> 1;
    // Go to the left and right child of
    // current node
    build(arr, low, mid, 2 * ind + 1);
    build(arr, mid + 1, high, 2 * ind + 2);
 
    // Calculate count of primorials for
    // internal node of segment tree for
    // corresponding ranges
 
    segment[ind]
        = segment[2 * ind + 1]
          + segment[2 * ind + 2];
}
 
// To update segment tree nodes
void update(int low, int high, int ind,
            int pos, int val)
{
    if (low == high) {
        // If new assign value is primorial
        // then mark it 1 otherwise 0
        auto it = primorial.find(val);
        if (it != primorial.end())
            segment[ind] = 1;
        else
            segment[ind] = 0;
        return;
    }
 
    int mid = (low + high) >> 1;
 
    // Go to the left child if pos is on
    // the left side of current node
    if (pos >= low && pos <= mid)
        update(low, mid, 2 * ind + 1,
               pos, val);
    // Go to the right child if pos is on
    // the right side
    else
        update(mid + 1, high, 2 * ind + 2,
               pos, val);
 
    // Upadte all internal nodes of segment
    // tree
    segment[ind]
        = segment[2 * ind + 1]
          + segment[2 * ind + 2];
}
 
// To compute answer for given range l to r
int range_queries(int l, int r, int low,
                  int high, int ind)
{
    // [l, r] is given range, [low, high] is
    // current range if current range is
    // invalid return 0
    if (high < l || low > r)
        return 0;
 
    // If current range is completly inside of
    // the given range then return value of
    // that node
    if (low >= l && high <= r)
        return segment[ind];
 
    int mid = (low + high) >> 1;
    // Go to the left child and right child
    // to compute answer
    return (
        range_queries(l, r, low, mid,
                      2 * ind + 1)
        + range_queries(l, r, mid + 1, high,
                        2 * ind + 2));
}
 
// Function to find the count of primorials
vector count(int arr[], int N,
                  vector >& queries)
{
    vector ans;
 
    // Mark prime numbers as a true
    sieve();
    // To precompute primorials
    store_primorials();
 
    // Build segment tree for given array
    build(arr, 0, N - 1, 0);
 
    for (int i = 0; i < queries.size(); i++) {
        if (queries[i][0] == 1) {
            int l = queries[i][1];
            int r = queries[i][2];
            int x = range_queries(l, r, 0,
                                  N - 1, 0);
            ans.push_back(x);
        }
        else {
            update(0, N - 1, 0, queries[i][1],
                   queries[i][2]);
        }
    }
    return ans;
}
 
// Driver Code
int main()
{
    // Consider 0 based indexing
    int arr[] = { 25, 2, 7, 30, 1 };
    int N = sizeof(arr) / sizeof(arr[0]);
    vector > queries{ { 1, 1, 4 },
                                  { 2, 2, 6 },
                                  { 1, 0, 3 } };
 
    vector ans = count(arr, N, queries);
    for (int x : ans)
        cout << x << " ";
    return 0;
}


Python3
# python3 code to count primorials
# in the given range for Q queries
mxx = int(1e6 + 3)
isPrime = [True for _ in range(1000)]
segment = [0 for _ in range(4 * mxx)]
primorial = {}
 
# Mark true all prime numbers
def sieve():
    global mxx, isprime, segment, primorial
    isPrime[0] = isPrime[1] = False
    for i in range(2, 1000):
        if (isPrime[i]):
            for j in range(2*i, 1000, i):
               
                # Mark false which are the
                # multiple of prime numbers
                isPrime[j] = False
 
# Store primorials
def store_primorials():
 
    global mxx, isprime, segment, primorial
    cnt = 0
    product = 1
    for i in range(2, mxx):
        if cnt >= 15:
            break
 
        if (isPrime[i]):
            product = product * i
            primorial[product] = primorial[product] + \
                1 if product in primorial else 1
            cnt += 1
 
# To build segment tree
def build(arr, low, high, ind):
    global mxx, isprime, segment, primorial
     
    # The node is leaf node
    if (low == high):
       
        # If array value is primorial
        # assign leaf node value 1
        # otherwise 0
 
        if (arr[low] in primorial):
            segment[ind] = 1
        else:
            segment[ind] = 0
        return
 
    mid = (low + high) >> 1
     
    # Go to the left and right child of
    # current node
    build(arr, low, mid, 2 * ind + 1)
    build(arr, mid + 1, high, 2 * ind + 2)
 
    # Calculate count of primorials for
    # internal node of segment tree for
    # corresponding ranges
    segment[ind] = segment[2 * ind + 1] + segment[2 * ind + 2]
 
# To update segment tree nodes
def update(low, high, ind, pos, val):
    global mxx, isprime, segment, primorial
    if (low == high):
       
        # If new assign value is primorial
        # then mark it 1 otherwise 0
        if (val in primorial):
            segment[ind] = 1
        else:
            segment[ind] = 0
        return
 
    mid = (low + high) >> 1
 
    # Go to the left child if pos is on
    # the left side of current node
    if (pos >= low and pos <= mid):
        update(low, mid, 2 * ind + 1,
               pos, val)
         
    # Go to the right child if pos is on
    # the right side
    else:
        update(mid + 1, high, 2 * ind + 2,
               pos, val)
 
    # Upadte all internal nodes of segment
    # tree
    segment[ind] = segment[2 * ind + 1] + segment[2 * ind + 2]
 
# To compute answer for given range l to r
def range_queries(l, r, low, high, ind):
    global mxx, isprime, segment, primorial
     
    # [l, r] is given range, [low, high] is
    # current range if current range is
    # invalid return 0
    if (high < l or low > r):
        return 0
 
    # If current range is completly inside of
    # the given range then return value of
    # that node
    if (low >= l and high <= r):
        return segment[ind]
 
    mid = (low + high) >> 1
     
    # Go to the left child and right child
    # to compute answer
    return (
        range_queries(l, r, low, mid,
                      2 * ind + 1)
        + range_queries(l, r, mid + 1, high,
                        2 * ind + 2))
 
# Function to find the count of primorials
def count(arr, N, queries):
    global mxx, isprime, segment, primorial
    ans = []
 
    # Mark prime numbers as a true
    sieve()
     
    # To precompute primorials
    store_primorials()
 
    # Build segment tree for given array
    build(arr, 0, N - 1, 0)
 
    for i in range(0, len(queries)):
        if (queries[i][0] == 1):
            l = queries[i][1]
            r = queries[i][2]
            x = range_queries(l, r, 0,
                              N - 1, 0)
            ans.append(x)
 
        else:
            update(0, N - 1, 0, queries[i][1],
                   queries[i][2])
 
    return ans
 
# Driver Code
if __name__ == "__main__":
 
    # Consider 0 based indexing
    arr = [25, 2, 7, 30, 1]
    N = len(arr)
    queries = [[1, 1, 4], [2, 2, 6], [1, 0, 3]]
 
    ans = count(arr, N, queries)
    for x in ans:
        print(x, end=" ")
 
    # This code is contributed by rakeshsahni


输出
2 3 

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