Cuente los primoriales en el rango dado de Array cuando se permite la actualización

Dada una array que consta de N enteros positivos y Q consultas donde cada consulta es uno de los siguientes tipos:

  1. 1 lr : requiere imprimir el recuento de primoriales en el rango de índices [l, r] .
  2. 2 px : necesita asignar un valor x en un índice p dado .

Ejemplos:

Entrada: arr[] = {25, 2, 7, 30, 1} consultas = { {1, 1, 4 }, {2, 2, 6}, {1, 0, 3} }
Salida:  2 3
Explicación: En la primera consulta, busque primoriales del índice [1, 4]. 
Entonces, para índices en el rango [1, 4] solo 2 y 30. Estos dos elementos son primoriales porque 2 
es el primer número primo y 30 = 2*3*5 (producto de los primeros tres números primos). 
Entonces, la salida es 2 para esta consulta. 
En la segunda consulta, asigne un valor = 6 en el índice 2. Ahora la array se verá así: { 25, 2, 6, 30, 1}. 
En la tercera consulta, hay 3 números enteros que son primoriales en el rango [0, 3], es decir, {2, 6, 30}. Entonces la salida es 3.

Entrada: arr[] = {210, 2, 6, 30, 2310}, queries = { {1, 2, 4}, {1, 0, 4}}
Salida: 3 5
Explicación: Todos los elementos de la array anterior son primordial.
210 = 2*3*5*7
2310 = 2*3*5*7*11

 

Enfoque ingenuo: el enfoque básico es almacenar números primos en orden ascendente utilizando el método tamiz . Luego, para cada consulta del primer tipo, verifique todos los elementos en ese rango y encuentre el recuento de primoriales y para el segundo tipo de consulta, asigne ese valor al índice dado.

Siga los pasos a continuación para saber si un número es primorial o no: 

  • Comience desde el primer número primo almacenado.
  • Sigue multiplicando estos números primos almacenados.
  • Si en cualquier punto el producto de números primos se vuelve igual a arr[i], entonces arr[i] es un primorial.
  • Si el producto excede a arr[i], entonces arr[i] no es un primorial. 

Siga la ilustración a continuación para tener una mejor comprensión de cómo encontrar un primorial

Ilustración: 

Comprobar que arr[i]= 6 es primorial o no. inicialice cur con el primer número primo.
cur = 2; 
cur = cur * 3, entonces ahora cur tiene valor 6 y arr[ i ] = 6. Entonces arr[ i ] es primorial.

Para comprobar arr[i]= 10, es primorial o no. Inicialice cur con el primer primo 2.
cur = 2;
cur = cur * 3, entonces ahora cur tiene valor 6 
cur = cur * 5 = 6 * 5 = 30. 
Ahora cur tiene valor 30 y 30 es mayor que arr[i]. 
Entonces arr[i] = 10 no es un primorial. 

Complejidad temporal: O(Q * N)
Espacio auxiliar: O(1)

Enfoque eficiente: este problema se puede resolver de manera más eficiente al resolver las consultas en menos tiempo utilizando un árbol de segmentos basado en la siguiente observación:

Marque los primoriales presentes en la array y almacénelos en una estructura de datos de modo que podamos obtener el recuento de los primoriales dentro de un rango de índices y actualizar los valores cuando sea necesario en un tiempo óptimo.
Esta tarea se puede realizar mediante el uso de la estructura de datos del árbol de segmentos.

Siga el siguiente procedimiento para implementar la estructura de datos del árbol de segmentos.

  • Guarde los primeros 15 primoriales en ( porque el 15º primorial está en orden de 10 17
  • Marque los elementos de la array que son primoriales.
  • En el árbol de segmentos, los Nodes hoja almacenan si el elemento correspondiente de la array es primorial o no (almacena 1 si es primorial; de lo contrario almacena 0) y los Nodes internos almacenan cuántos primoriales hay en ese rango dado (es decir, almacenan la suma de sus Nodes secundarios).

El siguiente es el árbol de segmentos para el ejemplo dado arr[ ] = {25, 2, 7, 30, 1} :
(cnt representa el conteo de primoriales correspondientes al rango cubierto por ese Node)

 

Para la consulta de tipo 2, si el valor asignado x es primorial, almacene 1 correspondiente a ese Node hoja; de lo contrario, almacene 0. Luego actualice los Nodes internos hasta la raíz del árbol de segmentos. Esto actualizará los recuentos de los rangos.

Siga los pasos que se mencionan a continuación para implementar el enfoque:

A continuación se muestra la implementación del enfoque anterior.

C++

// C++ code to count primorials
// in the given range for Q queries
 
#include <bits/stdc++.h>
using namespace std;
const int mxx = 1e6 + 3;
vector<bool> isPrime(1000, true);
int segment[4 * mxx];
unordered_map<long long, int> 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);
 
    // Update 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 completely 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<int> count(int arr[], int N,
                  vector<vector<int> >& queries)
{
    vector<int> 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<vector<int> > queries{ { 1, 1, 4 },
                                  { 2, 2, 6 },
                                  { 1, 0, 3 } };
 
    vector<int> 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)
 
    # Update 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 completely 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

Javascript

<script>
// JavaScript code to count primorials
// in the given range for Q queries
 
let mxx = 1e6 + 3;
var isPrime = new Array(1000).fill(true);
var segment = new Array(4 * mxx).fill(0);
var primorial = {};
 
// Mark true all prime numbers
function sieve()
{
    isPrime[0] = false;
    isPrime[1] = false;
    for (var i = 2; i < 1000; i++) {
        if (isPrime[i]) {
            for (var j = 2 * i; j < 1000; j = j + i)
                // Mark false which are the
                // multiple of prime numbers
                isPrime[j] = false;
        }
    }
}
 
// Store primorials
function store_primorials()
{
    var cnt = 0;
    var product = 1;
    for (var i = 2; i < mxx && cnt < 15; i++) {
        if (isPrime[i]) {
            product = product * 1 * i;
            if (primorial.hasOwnProperty(product))
                primorial[product]++;
            else
                primorial[product] = 1;
            cnt++;
        }
    }
}
 
// To build segment tree
function build(arr, low, high, ind)
{
    // The node is leaf node
    if (low == high) {
        // If array value is primorial
        // assign leaf node value 1
        // otherwise 0
        if (primorial.hasOwnProperty(arr[low]))
            segment[ind] = 1;
        else
            segment[ind] = 0;
        return;
    }
 
    var 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
function update(low, high, ind, pos, val)
{
    if (low == high) {
        // If new assign value is primorial
        // then mark it 1 otherwise 0
 
        if (primorial.hasOwnProperty(low))
            segment[ind] = 1;
        else
            segment[ind] = 0;
        return;
    }
 
    var 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);
 
    // Update 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
function range_queries(l, r, low, high, 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 completely inside of
    // the given range then return value of
    // that node
    if (low >= l && high <= r)
        return segment[ind];
 
    var 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
function count(arr, N, queries)
{
    var 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 (var i = 0; i < queries.length; i++) {
        if (queries[i][0] == 1) {
            var l = queries[i][1];
            var r = queries[i][2];
            var x = range_queries(l, r, 0, N - 1, 0);
            ans.push(x);
        }
        else {
            update(0, N - 1, 0, queries[i][1],
                   queries[i][2]);
        }
    }
    return ans;
}
 
// Driver Code
 
// Consider 0 based indexing
var arr = [ 25, 2, 7, 30, 1 ];
var N = arr.length;
var queries = [ [ 1, 1, 4 ], [ 2, 2, 6 ], [ 1, 0, 3 ] ];
 
var ans = count(arr, N, queries);
for (var i = 0; i < ans.length; i++)
    document.write(ans[i] + " ");
     
// This code is contributed by phasing17
</script>
Producción

2 3 

Complejidad de tiempo: O(Q * log(N))
Espacio auxiliar: O(N)

Publicación traducida automáticamente

Artículo escrito por patilnainesh911 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *