Consultas para encontrar el par máximo de productos en el rango con actualizaciones

Dada una array de N enteros positivos. La tarea es realizar las siguientes operaciones según el tipo de consulta dada. 
1. Imprime el par máximo de productos en un rango dado. [LR] 
2. Actualizar A i con algún valor dado. 
Ejemplos: 
 

Entrada: A={1, 3, 4, 2, 5} 
Consultas: 
Tipo 1: L = 0, R = 2. 
Tipo 2: i = 1, val = 6 
Tipo 1: L = 0, R = 2.
Salida : 
12 
24
Para la consulta 1, el producto máximo en un rango [0, 2] es 3*4 = 12. 
Para la consulta 2, después de una actualización, la array se convierte en [1, 6, 4, 2, 5] 
Para la consulta 3 , el producto máximo en un rango [0, 2] es 6*4 = 24. 
 

Solución ingenua : el enfoque de fuerza bruta es atravesar de L a R y verificar cada par y luego encontrar el par de productos máximo entre ellos. 
Complejidad de tiempo : O (N ^ 2) para cada consulta. 
Una mejor solución es encontrar el primer y el segundo número más grande en el rango de L a R recorriendo y luego devolviendo su producto. 
Complejidad de tiempo : O(N) para cada consulta. 
Una solución eficiente es utilizar un árbol de segmentos para almacenar el mayor y el segundo mayor número en los Nodes y luego devolver el producto de ellos. 
A continuación se muestra la implementación del enfoque anterior. 
 

CPP

// C++ program to find the maximum
// product in a range with updates
#include <bits/stdc++.h>
using namespace std;
#define ll long long
  
// structure defined
struct segment {
    // l for largest
    // sl for second largest
    ll l;
    ll sl;
};
  
// function to perform queries
segment query(segment* tree, ll index,
              ll s, ll e, ll qs, ll qe)
{
  
    segment res;
    res.l = -1;
    res.sl = -1;
    // no overlapping case
    if (qs > e || qe < s || s > e) {
  
        return res;
    }
  
    // complete overlap case
    if (s >= qs && e <= qe) {
  
        return tree[index];
    }
  
    // partial overlap case
    ll mid = (s + e) / 2;
  
    // calling left node and right node
    segment left = query(tree, 2 * index,
                         s, mid, qs, qe);
    segment right = query(tree, 2 * index + 1,
                          mid + 1, e, qs, qe);
  
    // largest of ( left.l, right.l)
    ll largest = max(left.l, right.l);
  
    // compute second largest
    // second largest will be minimum
    // of maximum from left and right node
    ll second_largest = min(max(left.l, right.sl),
                            max(right.l, left.sl));
  
    // store largest and
    // second_largest in res
    res.l = largest;
    res.sl = second_largest;
  
    // return the resulting node
    return res;
}
  
// function to update the query
void update(segment* tree, ll index,
            ll s, ll e, ll i, ll val)
{
    // no overlapping case
    if (i < s || i > e) {
        return;
    }
  
    // reached leaf node
  
    if (s == e) {
        tree[index].l = val;
        tree[index].sl = INT_MIN;
        return;
    }
  
    // partial overlap
  
    ll mid = (s + e) / 2;
  
    // left subtree call
    update(tree, 2 * index, s, mid, i, val);
  
    // right subtree call
    update(tree, 2 * index + 1, mid + 1, e, i, val);
  
    // largest of ( left.l, right.l)
    tree[index].l = max(tree[2 * index].l, tree[2 * index + 1].l);
  
    // compute second largest
    // second largest will be
    // minimum of maximum from left and right node
  
    tree[index].sl = min(max(tree[2 * index].l, tree[2 * index + 1].sl),
                         max(tree[2 * index + 1].l, tree[2 * index].sl));
}
  
// Function to build the tree
void buildtree(segment* tree, ll* a, ll index, ll s, ll e)
{
    // tree is build bottom to up
    if (s > e) {
        return;
    }
  
    // leaf node
    if (s == e) {
        tree[index].l = a[s];
        tree[index].sl = INT_MIN;
        return;
    }
  
    ll mid = (s + e) / 2;
  
    // calling the left node
    buildtree(tree, a, 2 * index, s, mid);
  
    // calling the right node
    buildtree(tree, a, 2 * index + 1, mid + 1, e);
  
    // largest of ( left.l, right.l)
    ll largest = max(tree[2 * index].l, tree[2 * index + 1].l);
  
    // compute second largest
    // second largest will be minimum
    // of maximum from left and right node
    ll second_largest = min(max(tree[2 * index].l, tree[2 * index + 1].sl),
                            max(tree[2 * index + 1].l, tree[2 * index].sl));
  
    // storing the largest and
    // second_largest values in the current node
    tree[index].l = largest;
    tree[index].sl = second_largest;
}
  
// Driver Code
int main()
{
  
    // your code goes here
    ll n = 5;
  
    ll a[5] = { 1, 3, 4, 2, 5 };
  
    // allocating memory for segment tree
    segment* tree = new segment[4 * n + 1];
  
    // buildtree(tree, a, index, start, end)
    buildtree(tree, a, 1, 0, n - 1);
  
    // query section
    // storing the resulting node
    segment res = query(tree, 1, 0, n - 1, 0, 2);
  
    cout << "Maximum product in the range "
         << "0 and 2 before update: " << (res.l * res.sl);
  
    // update section
    // update(tree, index, start, end, i, v)
    update(tree, 1, 0, n - 1, 1, 6);
  
    res = query(tree, 1, 0, n - 1, 0, 2);
  
    cout << "\nMaximum product in the range "
         << "0 and 2 after update: " << (res.l * res.sl);
  
    return 0;
}
Producción: 

Maximum product in the range 0 and 2 before update: 12
Maximum product in the range 0 and 2 after update: 24

 

Complejidad de tiempo : O (log N) por consulta y O (N) para construir el árbol.
 

Tema relacionado: Árbol de segmentos

Publicación traducida automáticamente

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