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.- 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 - 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 - 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. - 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.
- Caso 1: si x e y son números cuadrados perfectos
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>
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