Suma de intervalo y actualización con número de divisores

Dada una array A de N enteros. Debe responder dos tipos de consultas:
1. Actualizar [l, r]: para cada i en el rango de l a r, actualice A i con D (A i ), donde D (A i ) representa el número de divisores de A i
2. Consulta [l, r]: calcule la suma de todos los números comprendidos entre l y r en la array A.
La entrada se proporciona como dos números enteros N y Q, que representan el número de enteros en la array y el número de consultas, respectivamente. La siguiente línea contiene una array de n enteros seguida de Q consultas donde la i-ésima consulta se representa como tipo i , li , r i .

Requisito previo: árboles indexados binarios | Árboles de segmento

Ejemplos:

Input : 7 4
        6 4 1 10 3 2 4
        2 1 7
        2 4 5
        1 3 5
        2 4 4
Output : 30
         13
         4

Explicación: la primera consulta es para calcular la suma de números de A 1 a A 7 , que es 6 + 4
+ 1 + 10 + 3 + 2 + 4 = 30. De manera similar, la segunda consulta da como resultado 13. Para la tercera consulta,
que es actualizar operación, por lo tanto, A 3 seguirá siendo 1, A 4 se convertirá en 4 y A 5 se convertirá en 2. La
cuarta consulta dará como resultado A 4 = 4.

Enfoque ingenuo:
una solución simple es ejecutar un ciclo de l a r y calcular la suma de los elementos en un rango dado. Para actualizar un valor, calcule previamente los valores del número de divisores de cada número y simplemente haga arr[i] = divisores[arr[i]].

Enfoque eficiente:
La idea es reducir la complejidad del tiempo para cada consulta y actualizar la operación a O(logN). Utilice árboles indexados binarios (BIT) o árboles de segmentos. Construya una array BIT[] y tenga dos funciones para la operación de consulta y actualización y calcule previamente la cantidad de divisores para cada número. Ahora, para cada operación de actualización, la observación clave es que los números ‘1’ y ‘2’ tendrán ‘1’ y ‘2’ como su número de divisores respectivamente, por lo que si existe en el rango de consulta de actualización, no t necesita ser actualizado. Usaremos un conjunto para almacenar el índice de solo aquellos números que son mayores que 2 y usaremos la búsqueda binaria para encontrar el índice l de la consulta de actualización e incrementar el índice l hasta que cada elemento se actualice en el rango de esa consulta de actualización. Si el arr[i] tiene solo 2 divisores, luego de actualizarlo, elimínelo del conjunto, ya que siempre será 2, incluso después de cualquier consulta de actualización siguiente. Para la operación de consulta de suma, simplemente haga consulta (r) – consulta (l – 1).

// CPP program to calculate sum 
// in an interval and update with
// number of divisors
#include <bits/stdc++.h>
using namespace std;
  
int divisors[100], BIT[100];
  
// structure for queries with members type, 
// leftIndex, rightIndex of the query
struct queries
{
    int type, l, r;
};
  
// function to calculate the number 
// of divisors of each number
void calcDivisors()
{
    for (int i = 1; i < 100; i++) {
        for (int j = i; j < 100; j += i) {
            divisors[j]++; 
        }
    }
}
  
// function for updating the value
void update(int x, int val, int n)
{
    for (x; x <= n; x += x&-x) {
        BIT[x] += val;
    }
}
  
// function for calculating the required 
// sum between two indexes
int sum(int x)
{
    int s = 0;
    for (x; x > 0; x -= x&-x) {
        s += BIT[x]; 
    }
    return s;
}
  
// function to return answer to queries
void answerQueries(int arr[], queries que[], int n, int q)
{
    // Declaring a Set
    set<int> s;
    for (int i = 1; i < n; i++) {
          
        // inserting indexes of those numbers 
        // which are greater than 2
        if(arr[i] > 2) s.insert(i);
        update(i, arr[i], n);
    }
      
    for (int i = 0; i < q; i++) {
          
        // update query
        if (que[i].type == 1) { 
            while (true) {
                  
                // find the left index of query in 
                // the set using binary search
                auto it = s.lower_bound(que[i].l);
                  
                // if it crosses the right index of 
                // query or end of set, then break
                if(it == s.end() || *it > que[i].r) break;
                  
                que[i].l = *it;
                  
                // update the value of arr[i] to 
                // its number of divisors
                update(*it, divisors[arr[*it]] - arr[*it], n);
                  
                arr[*it] = divisors[arr[*it]];
                  
                // if updated value becomes less than or 
                // equal to 2 remove it from the set
                if(arr[*it] <= 2) s.erase(*it);
                  
                // increment the index
                que[i].l++;
            }
        }
          
        // sum query
        else {
            cout << (sum(que[i].r) - sum(que[i].l - 1)) << endl;
        }
    }
}
  
// Driver Code
int main() 
{
    // precompute the number of divisors for each number
    calcDivisors(); 
      
    int q = 4;
      
    // input array
    int arr[] = {0, 6, 4, 1, 10, 3, 2, 4};
    int n = sizeof(arr) / sizeof(arr[0]);
      
    // declaring array of structure of type queries
    queries que[q + 1]; 
      
    que[0].type = 2, que[0].l = 1, que[0].r = 7;
    que[1].type = 2, que[1].l = 4, que[1].r = 5;
    que[2].type = 1, que[2].l = 3, que[2].r = 5;
    que[3].type = 2, que[3].l = 4, que[3].r = 4;
      
    // answer the Queries
    answerQueries(arr, que, n, q);
      
    return 0;
}
Producción:

30
13
4

La Complejidad de Tiempo para responder consultas Q será O(Q * log(N)).

Publicación traducida automáticamente

Artículo escrito por Nishant Tanwar 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 *