Consultas de rango de array para encontrar la cantidad de elementos cuadrados perfectos con actualizaciones

Dada una array arr[] de N enteros, la tarea es realizar las siguientes dos consultas: 

  • consulta (inicio, final) : Imprime la cantidad de números cuadrados perfectos en el subarreglo de principio a fin
  • update(i, x) : agregue x al elemento de array al que hace referencia el índice de array i , es decir: arr[i] = x

Nota: en el siguiente ejemplo se sigue la indexación basada en 0.

Ejemplo: 

Entrada: arr = [ 16, 15, 8, 9, 14, 25 ]; 
Consulta 1: consulta (inicio = 0, final = 4) 
Consulta 2: actualización (i = 3, x = 11) es decir, arr[3]=11  
Consulta 3: consulta (inicio = 0, final = 4) 
Salida: 2 1 
Explicación:
en la Consulta 1 , el subarreglo [0…4] tiene 2 números cuadrados perfectos 16 y 9, a saber. [ 16, 15, 8, 9, 14 ]
En la Consulta 2 , el valor en el índice 3 se actualiza a 11,  
la array arr ahora es, [ 16, 15, 8, 11, 14, 25 ]
En la Consulta 3 , el sub -array [0…4] tiene 1 cuadrado perfecto número 16 a saber. [16, 15, 8, 11, 14]
 

Acercarse: 

Para manejar actualizaciones de puntos y consultas de rango, un árbol de segmentos es óptimo para este propósito.
Para verificar números cuadrados perfectos, la idea es calcular primero la raíz cuadrada del número y si la raíz cuadrada es un número entero, entonces el elemento actual es un cuadrado perfecto; de lo contrario, no lo es. Si el elemento actual es un cuadrado perfecto, configúrelo en 1, de lo contrario, en 0.

Construyendo el árbol de segmentos: 

  • El problema ahora se reduce a la suma del subarreglo utilizando el problema del árbol de segmentos.
  • Ahora, podemos construir el árbol de segmentos donde un Node de hoja se representa como 0 (si no es un número cuadrado perfecto) o 1 (si es un número cuadrado perfecto).
  • Los Nodes internos del árbol de segmentos son iguales a la suma de sus Nodes secundarios, por lo que un Node representa los números cuadrados perfectos totales en el rango de L a R con el rango [L, R] debajo de este Node y el subárbol debajo de él .

Manejo de consultas y actualizaciones de puntos: 

  • Cada vez que recibimos una consulta de principio a fin, podemos consultar el árbol de segmentos para la suma de Nodes en el rango de principio a fin, que a su vez representa la cantidad de números cuadrados perfectos en el rango de principio a fin.
  • Para realizar una actualización de puntos y actualizar el valor en el índice i a x, verificamos los siguientes casos: 
    Deje que el valor anterior de arr[i] sea y y el nuevo valor sea x. 
    1. Caso 1: si x e y son números cuadrados perfectos 
      El recuento de números cuadrados perfectos en el subarreglo no cambia, así que solo actualizamos el arreglo y no modificamos el árbol de segmentos
    2. Caso 2: si x e y no son números cuadrados perfectos 
      El recuento de números cuadrados perfectos en el subarreglo no cambia, así que solo actualizamos el arreglo y no modificamos el árbol de segmentos
    3. Caso 3: si y es un número cuadrado perfecto pero x no lo es 
      . La cantidad de números cuadrados perfectos en el subarreglo disminuye, por lo que actualizamos el arreglo y agregamos -1 a cada rango. El índice i que se va a actualizar forma parte del árbol de segmentos.
    4. Caso 4: si y no es un número cuadrado perfecto pero x es un número cuadrado perfecto 
      El recuento de números cuadrados perfectos en el subarreglo aumenta, por lo que actualizamos el arreglo y agregamos 1 a cada rango. El índice i que se va a actualizar forma parte del árbol de segmentos.

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

C++

// C++ program to find number of
// perfect square numbers in a
// subarray and performing updates
 
#include <bits/stdc++.h>
using namespace std;
 
#define MAX 1000
 
// Function to check if a number is
// a perfect square or not
bool isPerfectSquare(long long int x)
{
    // Find floating point value of
    // square root of x.
    long double sr = sqrt(x);
 
    // If square root is an integer
    return ((sr - floor(sr)) == 0)
               ? true
               : false;
}
 
// A utility function to get the middle
// index from corner indexes.
int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
// Recursive function to get the number
// of perfect square numbers in a given
// range
/* where
  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 queryUtil(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 perfect square numbers
    // 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 queryUtil(st, ss, mid, qs,
                     qe, 2 * index + 1)
           + queryUtil(st, mid + 1, se,
                       qs, qe, 2 * index + 2);
}
 
// Recursive function to update
// the nodes which have the given
// index in their range.
/* where
   st, si, ss & 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);
    }
}
 
// Function to update a value in the
// 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)
{
    // 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 perfect square numbers
    if (isPerfectSquare(oldValue)
        && isPerfectSquare(new_val))
        return;
 
    // Case 2: Old and new values
    // both not perfect square numbers
    if (!isPerfectSquare(oldValue)
        && !isPerfectSquare(new_val))
        return;
 
    // Case 3: Old value was perfect square,
    // new value is not a perfect square
    if (isPerfectSquare(oldValue)
        && !isPerfectSquare(new_val)) {
        diff = -1;
    }
 
    // Case 4: Old value was
    // non-perfect square,
    // new_val is perfect square
    if (!isPerfectSquare(oldValue)
        && !isPerfectSquare(new_val)) {
        diff = 1;
    }
 
    // Update values of nodes in segment tree
    updateValueUtil(st, 0, n - 1, i, diff, 0);
}
 
// Return no. of perfect square numbers
// in range from index qs (query start)
// to qe (query end).
// It mainly uses queryUtil()
void query(int* st, int n,
           int qs, int qe)
{
 
    int perfectSquareInRange
        = queryUtil(
            st, 0, n - 1, qs, qe, 0);
 
    cout << perfectSquareInRange << "\n";
}
 
// 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)
{
    // If there is one element in array,
    // check if it is perfect square number
    // then store 1 in the segment tree
    // else store 0 and return
    if (ss == se) {
 
        // if arr[ss] is a perfect
        // square number
        if (isPerfectSquare(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)
          + constructSTUtil(arr, mid + 1,
                            se, st, si * 2 + 2);
    return st[si];
}
 
// Function to construct a 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)
{
 
    // 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);
 
    // Return the constructed segment tree
    return st;
}
 
// Driver Code
int main()
{
    int arr[] = { 16, 15, 8, 9, 14, 25 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    // Build segment tree from given array
    int* st = constructST(arr, n);
 
    // Query 1: Query(start = 0, end = 4)
    int start = 0;
    int end = 4;
    query(st, n, start, end);
 
    // Query 2: Update(i = 3, x = 11),
    // i.e Update a[i] to x
    int i = 3;
    int x = 11;
    updateValue(arr, st, n, i, x);
 
    // 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;
    query(st, n, start, end);
 
    return 0;
}

Java

// Java program to find number of
// perfect square numbers in a
// subarray and performing updates
import java.util.*;
class GFG{
 
static final int MAX = 1000;
 
// Function to check if a number is
// a perfect square or not
static boolean isPerfectSquare(int x)
{
  // Find floating point value of
  // square root of x.
  double sr = Math.sqrt(x);
 
  // If square root is an integer
  return ((sr - Math.floor(sr)) == 0) ?
           true : false;
}
 
// A utility function to get
// the middle index from
// corner indexes.
static int getMid(int s,
                  int e)
{
  return s + (e - s) / 2;
}
 
// Recursive function to get the number
// of perfect square numbers in a given
// range
/* where
  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 queryUtil(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 perfect square numbers
  // 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 queryUtil(st, ss, mid, qs,
                   qe, 2 * index + 1) +
         queryUtil(st, mid + 1, se,
                   qs, qe, 2 * index + 2);
}
 
// Recursive function to update
// the nodes which have the given
// index in their range.
/* where
   st, si, ss & 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);
  }
}
 
// Function to update a value in the
// 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)
{
  // Check for erroneous
  // input index
  if (i < 0 || i > n - 1)
  {
    System.out.printf("Invalid Input");
    return;
  }
 
  int diff = 0, oldValue;
  oldValue = arr[i];
 
  // Update the value in array
  arr[i] = new_val;
 
  // Case 1: Old and new values
  // both are perfect square numbers
  if (isPerfectSquare(oldValue) &&
      isPerfectSquare(new_val))
    return;
 
  // Case 2: Old and new values
  // both not perfect square numbers
  if (!isPerfectSquare(oldValue) &&
      !isPerfectSquare(new_val))
    return;
 
  // Case 3: Old value was perfect square,
  // new value is not a perfect square
  if (isPerfectSquare(oldValue) &&
      !isPerfectSquare(new_val))
  {
    diff = -1;
  }
 
  // Case 4: Old value was
  // non-perfect square,
  // new_val is perfect square
  if (!isPerfectSquare(oldValue) &&
      !isPerfectSquare(new_val))
  {
    diff = 1;
  }
 
  // Update values of nodes
  // in segment tree
  updateValueUtil(st, 0, n - 1,
                  i, diff, 0);
}
 
// Return no. of perfect square numbers
// in range from index qs (query start)
// to qe (query end).
// It mainly uses queryUtil()
static void query(int[] st, int n,
                  int qs, int qe)
{
  int perfectSquareInRange = queryUtil(st, 0,
                                       n - 1,
                                       qs, qe, 0);
  System.out.print(perfectSquareInRange + "\n");
}
 
// 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)
{
  // If there is one element
  // in array, check if it is
  // perfect square number
  // then store 1 in the
  //segment tree else
  // store 0 and return
  if (ss == se)
  {
    // if arr[ss] is a perfect
    // square number
    if (isPerfectSquare(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) +
            constructSTUtil(arr, mid + 1,
                            se, st, si * 2 + 2);
  return st[si];
}
 
// Function to construct a 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)
{
  // Allocate memory for segment tree
  // Height of segment tree
  int x = (int)(Math.ceil(Math.log(n)));
 
  // Maximum size of segment tree
  int max_size = 4 * (int)Math.pow(2, x) + 1;
 
  int []st = new int[max_size];
 
  // Fill the allocated memory st
  constructSTUtil(arr, 0, n - 1, st, 0);
 
  // Return the constructed segment tree
  return st;
}
 
// Driver Code
public static void main(String[] args)
{
  int arr[] = {16, 15, 8, 9, 14, 25};
  int n = arr.length;
 
  // Build segment tree from
  // given array
  int []st = constructST(arr, n);
 
  // Query 1: Query
  // (start = 0, end = 4)
  int start = 0;
  int end = 4;
  query(st, n, start, end);
 
  // Query 2: Update(i = 3, x = 11),
  // i.e Update a[i] to x
  int i = 3;
  int x = 11;
  updateValue(arr, st, n, i, x);
 
  // uncomment to see array after
  // update for(int i = 0; i < n; i++)
  // System.out.print(arr[i]+ " ");
 
  // Query 3: Query(start = 0, end = 4)
  start = 0;
  end = 4;
  query(st, n, start, end);
}
}
 
// This code is contributed by Rajput-Ji

Python3

# Python program to find number of
# perfect square numbers in a
# subarray and performing updates
from math import sqrt, floor, ceil, log2
from typing import List
MAX = 1000
 
# Function to check if a number is
# a perfect square or not
def isPerfectSquare(x: int) -> bool:
 
    # Find floating point value of
    # square root of x.
    sr = sqrt(x)
 
    # If square root is an integer
    return True if ((sr - floor(sr)) == 0) else False
 
# A utility function to get the middle
# index from corner indexes.
def getMid(s: int, e: int) -> int:
    return s + (e - s) // 2
 
# Recursive function to get the number
# of perfect square numbers in a given
# range
''' where
  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 queryUtil(st: List[int], ss: int, se: int,
              qs: int, qe: int,
              index: int) -> int:
 
    # If segment of this node is a part
    # of given range, then return
    # the number of perfect square numbers
    # 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 queryUtil(st, ss, mid, qs, qe, 2 * index + 1) + queryUtil(
        st, mid + 1, se, qs, qe, 2 * index + 2)
 
 
# Recursive function to update
# the nodes which have the given
# index in their range.
''' where
   st, si, ss & 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: List[int], ss: int, se: int,
                    i: int, diff: int,
                    si: int) -> None:
 
    # 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)
 
 
# Function to update a value in the
# input array and segment tree.
# It uses updateValueUtil() to update
# the value in segment tree
def updateValue(arr: List[int], st: List[int],
                n: int, i: int,
                new_val: int) -> None:
 
    # Check for erroneous input index
    if (i < 0 or i > n - 1):
        print("Invalid Input")
        return
 
    diff = 0
    oldValue = 0
 
    oldValue = arr[i]
 
    # Update the value in array
    arr[i] = new_val
 
    # Case 1: Old and new values
    # both are perfect square numbers
    if (isPerfectSquare(oldValue) and isPerfectSquare(new_val)):
        return
 
    # Case 2: Old and new values
    # both not perfect square numbers
    if (not isPerfectSquare(oldValue) and not isPerfectSquare(new_val)):
        return
 
    # Case 3: Old value was perfect square,
    # new value is not a perfect square
    if (isPerfectSquare(oldValue) and not isPerfectSquare(new_val)):
        diff = -1
 
    # Case 4: Old value was
    # non-perfect square,
    # new_val is perfect square
    if (not isPerfectSquare(oldValue) and not isPerfectSquare(new_val)):
        diff = 1
 
    # Update values of nodes in segment tree
    updateValueUtil(st, 0, n - 1, i, diff, 0)
 
 
# Return no. of perfect square numbers
# in range from index qs (query start)
# to qe (query end).
# It mainly uses queryUtil()
def query(st: List[int], n: int, qs: int, qe: int) -> None:
 
    perfectSquareInRange = queryUtil(st, 0, n - 1, qs, qe, 0)
 
    print(perfectSquareInRange)
 
 
# Recursive function that constructs
# Segment Tree for array[ss..se].
# si is index of current node
# in segment tree st
def constructSTUtil(arr: List[int], ss: int, se: int, st: List[int],
                    si: int) -> int:
 
    # If there is one element in array,
    # check if it is perfect square number
    # then store 1 in the segment tree
    # else store 0 and return
    if (ss == se):
 
        # if arr[ss] is a perfect
        # square number
        if (isPerfectSquare(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) + constructSTUtil(
        arr, mid + 1, se, st, si * 2 + 2)
    return st[si]
 
# Function to construct a segment
# tree from given array. This
# function allocates memory for
# segment tree and calls
# constructSTUtil() to fill
# the allocated memory
def constructST(arr: List[int], n: int) -> List[int]:
 
    # Allocate memory for segment tree
    # Height of segment tree
    x = (ceil(log2(n)))
 
    # Maximum size of segment tree
    max_size = 2 * pow(2, x) - 1
 
    st = [0 for _ in range(max_size)]
 
    # Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0)
 
    # Return the constructed segment tree
    return st
 
# Driver Code
if __name__ == "__main__":
 
    arr = [16, 15, 8, 9, 14, 25]
    n = len(arr)
 
    # Build segment tree from given array
    st = constructST(arr, n)
 
    # Query 1: Query(start = 0, end = 4)
    start = 0
    end = 4
    query(st, n, start, end)
 
    # Query 2: Update(i = 3, x = 11),
    # i.e Update a[i] to x
    i = 3
    x = 11
    updateValue(arr, st, n, i, x)
 
    # 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
    query(st, n, start, end)
 
# This code is contributed by sanjeev2552

C#

// C# program to find number of
// perfect square numbers in a
// subarray and performing updates
using System;
class GFG{
 
static readonly int MAX = 1000;
 
// Function to check if a number
// is a perfect square or not
static bool isPerfectSquare(int x)
{
  // Find floating point value of
  // square root of x.
  double sr = Math.Sqrt(x);
 
  // If square root is an integer
  return ((sr - Math.Floor(sr)) == 0) ?
           true : false;
}
 
// A utility function to get
// the middle index from
// corner indexes.
static int getMid(int s,
                  int e)
{
  return s + (e - s) / 2;
}
 
// Recursive function to get the number
// of perfect square numbers in a given
// range
/* where
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 queryUtil(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 perfect square numbers
  // 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 queryUtil(st, ss, mid, qs,
                   qe, 2 * index + 1) +
         queryUtil(st, mid + 1, se,
                   qs, qe, 2 * index + 2);
}
 
// Recursive function to update
// the nodes which have the given
// index in their range.
/* where
st, si, ss & 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);
  }
}
 
// Function to update a value in the
// 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)
{
  // Check for erroneous
  // input index
  if (i < 0 || i > n - 1)
  {
    Console.Write("Invalid Input");
    return;
  }
 
  int diff = 0, oldValue;
  oldValue = arr[i];
 
  // Update the value in array
  arr[i] = new_val;
 
  // Case 1: Old and new values
  // both are perfect square numbers
  if (isPerfectSquare(oldValue) &&
      isPerfectSquare(new_val))
    return;
 
  // Case 2: Old and new values
  // both not perfect square numbers
  if (!isPerfectSquare(oldValue) &&
      !isPerfectSquare(new_val))
    return;
 
  // Case 3: Old value was perfect
  // square, new value is not a
  // perfect square
  if (isPerfectSquare(oldValue) &&
      !isPerfectSquare(new_val))
  {
    diff = -1;
  }
 
  // Case 4: Old value was
  // non-perfect square,
  // new_val is perfect square
  if (!isPerfectSquare(oldValue) &&
      !isPerfectSquare(new_val))
  {
    diff = 1;
  }
 
  // Update values of nodes
  // in segment tree
  updateValueUtil(st, 0, n - 1,
                  i, diff, 0);
}
 
// Return no. of perfect square numbers
// in range from index qs (query start)
// to qe (query end).
// It mainly uses queryUtil()
static void query(int[] st, int n,
                  int qs, int qe)
{
int perfectSquareInRange = queryUtil(st, 0,
                                     n - 1,
                                     qs, qe, 0);
Console.Write(perfectSquareInRange + "\n");
}
 
// 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)
{
  // If there is one element
  // in array, check if it is
  // perfect square number
  // then store 1 in the
  //segment tree else
  // store 0 and return
  if (ss == se)
  {
    // if arr[ss] is a perfect
    // square number
    if (isPerfectSquare(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) +
    constructSTUtil(arr, mid + 1,
                    se, st, si * 2 + 2);
  return st[si];
}
 
// Function to construct a 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)
{
// Allocate memory for segment tree
// Height of segment tree
int x = (int)(Math.Ceiling(Math.Log(n)));
 
// Maximum size of segment tree
int max_size = 4 * (int)Math.Pow(2,
                                 x) + 1;
 
int []st = new int[max_size];
 
// Fill the allocated
// memory st
constructSTUtil(arr, 0,
                n - 1,
                st, 0);
 
// Return the constructed
// segment tree
return st;
}
 
// Driver Code
public static void Main(String[] args)
{
  int []arr = {16, 15, 8, 9, 14, 25};
  int n = arr.Length;
 
  // Build segment tree
  // from given array
  int []st = constructST(arr, n);
 
  // Query 1: Query
  // (start = 0, end = 4)
  int start = 0;
  int end = 4;
  query(st, n, start, end);
 
  // Query 2: Update(i = 3,
  // x = 11), i.e Update a[i] to x
  int i = 3;
  int x = 11;
  updateValue(arr, st, n, i, x);
 
  // uncomment to see array after
  // update for(int i = 0; i < n; i++)
  // Console.Write(arr[i]+ " ");
 
  // Query 3: Query(start = 0,
  // end = 4)
  start = 0;
  end = 4;
  query(st, n, start, end);
}
}
 
// This code is contributed by Rajput-Ji

Javascript

<script>
// Javascript program to find number of
// perfect square numbers in a
// subarray and performing updates
let MAX = 1000;
 
// Function to check if a number is
// a perfect square or not
function isPerfectSquare(x)
{
 
    // Find floating point value of
    // square root of x.
    let sr = Math.sqrt(x);
 
    // If square root is an integer
    return ((sr - Math.floor(sr)) == 0) ?
        true : false;
}
 
// A utility function to get
// the middle index from
// corner indexes.
function getMid(s, e) {
    return Math.floor(s + (e - s) / 2);
}
 
// Recursive function to get the number
// of perfect square numbers in a given
// range
/* where
  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   */
function queryUtil(st, ss, se, qs, qe, index) {
    // If segment of this node is a part
    // of given range, then return
    // the number of perfect square numbers
    // 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
    let mid = getMid(ss, se);
    return queryUtil(st, ss, mid, qs,
        qe, 2 * index + 1) +
        queryUtil(st, mid + 1, se,
            qs, qe, 2 * index + 2);
}
 
// Recursive function to update
// the nodes which have the given
// index in their range.
/* where
   st, si, ss & 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
*/
function updateValueUtil(st, ss, se, i, diff, 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) {
        let mid = getMid(ss, se);
        updateValueUtil(st, ss, mid, i,
            diff, 2 * si + 1);
        updateValueUtil(st, mid + 1, se,
            i, diff, 2 * si + 2);
    }
}
 
// Function to update a value in the
// input array and segment tree.
// It uses updateValueUtil() to update
// the value in segment tree
function updateValue(arr, st, n, i, new_val) {
    // Check for erroneous
    // input index
    if (i < 0 || i > n - 1) {
        document.write("Invalid Input");
        return;
    }
 
    let diff = 0, oldValue;
    oldValue = arr[i];
 
    // Update the value in array
    arr[i] = new_val;
 
    // Case 1: Old and new values
    // both are perfect square numbers
    if (isPerfectSquare(oldValue) &&
        isPerfectSquare(new_val))
        return;
 
    // Case 2: Old and new values
    // both not perfect square numbers
    if (!isPerfectSquare(oldValue) &&
        !isPerfectSquare(new_val))
        return;
 
    // Case 3: Old value was perfect square,
    // new value is not a perfect square
    if (isPerfectSquare(oldValue) &&
        !isPerfectSquare(new_val)) {
        diff = -1;
    }
 
    // Case 4: Old value was
    // non-perfect square,
    // new_val is perfect square
    if (!isPerfectSquare(oldValue) &&
        !isPerfectSquare(new_val)) {
        diff = 1;
    }
 
    // Update values of nodes
    // in segment tree
    updateValueUtil(st, 0, n - 1,
        i, diff, 0);
}
 
// Return no. of perfect square numbers
// in range from index qs (query start)
// to qe (query end).
// It mainly uses queryUtil()
function query(st, n, qs, qe) {
    let perfectSquareInRange = queryUtil(st, 0,
        n - 1,
        qs, qe, 0);
    document.write(perfectSquareInRange + "<br>");
}
 
// Recursive function that constructs
// Segment Tree for array[ss..se].
// si is index of current node
// in segment tree st
function constructSTUtil(arr, ss, se, st, si) {
    // If there is one element
    // in array, check if it is
    // perfect square number
    // then store 1 in the
    //segment tree else
    // store 0 and return
    if (ss == se) {
        // if arr[ss] is a perfect
        // square number
        if (isPerfectSquare(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
    let mid = getMid(ss, se);
    st[si] = constructSTUtil(arr, ss,
        mid, st,
        si * 2 + 1) +
        constructSTUtil(arr, mid + 1,
            se, st, si * 2 + 2);
    return st[si];
}
 
// Function to construct a segment
// tree from given array. This
// function allocates memory for
// segment tree and calls
// constructSTUtil() to fill
// the allocated memory
function constructST(arr, n) {
    // Allocate memory for segment tree
    // Height of segment tree
    let x = (Math.ceil(Math.log(n)));
 
    // Maximum size of segment tree
    let max_size = 2 * Math.pow(2, x) - 1;
 
    let st = new Array(max_size).fill(0);
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0);
 
    // Return the constructed segment tree
    return st;
}
 
// Driver Code
 
let arr = [16, 15, 8, 9, 14, 25];
let n = arr.length;
 
// Build segment tree from
// given array
let st = constructST(arr, n);
 
// Query 1: Query
// (start = 0, end = 4)
let start = 0;
let end = 4;
query(st, n, start, end);
 
// Query 2: Update(i = 3, x = 11),
// i.e Update a[i] to x
let i = 3;
let x = 11;
updateValue(arr, st, n, i, x);
 
// uncomment to see array after
// update for(let i = 0; i < n; i++)
// System.out.print(arr[i]+ " ");
 
// Query 3: Query(start = 0, end = 4)
start = 0;
end = 4;
query(st, n, start, end);
 
// This code is contributed by Saurabh Jaiswal
</script>
Producción: 

2
1

 

Complejidad de tiempo: la complejidad de tiempo de cada consulta y actualización es O (log N) y la de construir el árbol de segmentos es O (N)

Publicación traducida automáticamente

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