Árbol indexado binario: actualización de rango y consultas de rango

Dada una matriz arr[0..N-1]. Es necesario realizar las siguientes operaciones. 

  1. actualizar(l r val) : Agregue 'val' a todos los elementos de la matriz desde [l r].
  2. obtenerSumaRango(l r) : Encuentre la suma de todos los elementos en la matriz de [l r].

Inicialmente, todos los elementos de la matriz son 0. Las consultas pueden realizarse en cualquier orden, es decir, puede haber muchas actualizaciones antes de la suma del rango.

Ejemplo:

Aporte: norte = 5   // {0 0 0 0 0}
Consultas: actualización: l = 0 r = 4 val = 2
               actualización: l = 3 r = 4 val = 3 
               obtenerSumaRango: l = 2 r = 4

Producción: La suma de los elementos del rango [2 4] es 12
Explicación: La matriz después de la primera actualización se convierte en {2 2 2 2 2}
La matriz después de la segunda actualización se convierte en {2 2 2 5 5}

Enfoque ingenuo: Para resolver el problema siga la siguiente idea:

En el publicación anterior Discutimos la actualización de rangos y las soluciones de consulta puntual utilizando BIT. 
rangeUpdate(l r val): Agregamos 'val' al elemento en el índice 'l'. Restamos 'val' del elemento en el índice 'r+1'. 
getElement(index) [o getSum()]: Devolvemos la suma de elementos desde 0 al índice que se puede obtener rápidamente usando BIT.
Podemos calcular rangeSum() usando consultas getSum(). 
rangoSuma(l r) = obtenerSuma(r) - obtenerSuma(l-1)

Una solución sencilla es utilizar las soluciones discutidas en el publicación anterior . La consulta de actualización de rango es la misma. La consulta de suma de rango se puede lograr realizando una consulta de obtención de todos los elementos del rango. 

Enfoque eficiente: Para resolver el problema siga la siguiente idea:

Obtenemos la suma del rango usando sumas de prefijo. ¿Cómo asegurarse de que la actualización se realice de manera que la suma del prefijo se pueda realizar rápidamente? Considere una situación en la que la suma del prefijo [0 k] (donde 0 <= k < n) is needed after range update on the range [l r]. Three cases arise as k can possibly lie in 3 regions.

  • Caso 1 : 0 < k < l 
    • La consulta de actualización no afectará la consulta de suma.
  • Caso 2 : yo <= k <= r 
    • Considere un ejemplo:  Sume 2 al rango [2 4] y la matriz resultante sería: 0 0 2 2 2
      Si k = 3 La suma de [0 k] = 4

¿Cómo obtener este resultado? 
Simplemente agregue el valor de l th índice de k th índice. La suma se incrementa en 'val*(k) - val*(l-1)' después de la consulta de actualización. 

  • Caso 3 : k > r 
    • Para este caso necesitamos agregar 'val' de l th índice de r th índice. La suma se incrementa en 'val*r – val*(l-1)' debido a una consulta de actualización.

Observaciones:  

Caso 1: es simple ya que la suma seguiría siendo la misma que antes de la actualización.

Caso 2: La suma se incrementó en val*k - val*(l-1). Podemos encontrar 'val', es similar a encontrar i th elemento en artículo de consulta de puntos y actualización de rango . Por lo tanto, mantenemos un BIT para la actualización de rango y consultas de puntos. Este BIT será útil para encontrar el valor en k. th índice. Ahora se calcula val * k ¿cómo manejar el término adicional val*(l-1)? 
Para gestionar este plazo adicional mantenemos otro BIT (BIT2). Actualizar val * (l-1) en l th index, por lo que cuando se realiza la consulta getSum en BIT2, el resultado será val*(l-1).

Caso 3: La suma en el caso 3 se incrementó en 'val*r - val *(l-1)'; el valor de este término se puede obtener usando BIT2. En lugar de sumar, restamos 'val*(l-1) - val*r' ya que podemos obtener este valor de BIT2 sumando val*(l-1) como hicimos en el caso 2 y restando val*r en cada operación de actualización.

Consulta de actualización 

Actualización (BITree1 l val)
Actualización (BITree1 r+1 -val)
ActualizaciónBIT2(BITree2 l val*(l-1))
ActualizaciónBIT2(BITree2 r+1 -val*r)

Suma de rango 

obtenerSuma(ÁrbolBIT1 k) *k) - obtenerSuma(ÁrbolBIT2 k)

Siga los pasos a continuación para resolver el problema:

  • Cree los dos árboles de índice binario usando la función dada constructBITree()
  • Para encontrar la suma en un rango determinado, llame a la función rangeSum() con parámetros como el rango dado y árboles indexados binarios.
    • Llame a una función suma que devolverá una suma en el rango [0 X]
    • Devolver suma(R) - suma(L-1)
      • Dentro de esta función llame a la función getSum() que devolverá la suma de la matriz de [0 X]
      • Devuelve obtenerSuma(Árbol1 x) * x - obtenerSuma(árbol2 x)
      • Dentro de la función getSum() cree una suma entera igual a cero y aumente el índice en 1
      • Mientras el índice sea mayor que cero aumente la suma en Árbol[índice]
      • Disminuya el índice en (index & (-index)) para mover el índice al nodo principal en el árbol
      • Suma de devolución
  • Imprime la suma en el rango dado

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

C++
   // C++ program to demonstrate Range Update   // and Range Queries using BIT   #include          using     namespace     std  ;   // Returns sum of arr[0..index]. This function assumes   // that the array is preprocessed and partial sums of   // array elements are stored in BITree[]   int     getSum  (  int     BITree  []     int     index  )   {      int     sum     =     0  ;     // Initialize result      // index in BITree[] is 1 more than the index in arr[]      index     =     index     +     1  ;      // Traverse ancestors of BITree[index]      while     (  index     >     0  )     {      // Add current element of BITree to sum      sum     +=     BITree  [  index  ];      // Move index to parent node in getSum View      index     -=     index     &     (  -  index  );      }      return     sum  ;   }   // Updates a node in Binary Index Tree (BITree) at given   // index in BITree. The given value 'val' is added to   // BITree[i] and all of its ancestors in tree.   void     updateBIT  (  int     BITree  []     int     n       int     index       int     val  )   {      // index in BITree[] is 1 more than the index in arr[]      index     =     index     +     1  ;      // Traverse all ancestors and add 'val'      while     (  index      <=     n  )     {      // Add 'val' to current node of BI Tree      BITree  [  index  ]     +=     val  ;      // Update index to that of parent in update View      index     +=     index     &     (  -  index  );      }   }   // Returns the sum of array from [0 x]   int     sum  (  int     x       int     BITTree1  []     int     BITTree2  [])   {      return     (  getSum  (  BITTree1       x  )     *     x  )     -     getSum  (  BITTree2       x  );   }   void     updateRange  (  int     BITTree1  []     int     BITTree2  []     int     n        int     val       int     l       int     r  )   {      // Update Both the Binary Index Trees      // As discussed in the article      // Update BIT1      updateBIT  (  BITTree1       n       l       val  );      updateBIT  (  BITTree1       n       r     +     1       -  val  );      // Update BIT2      updateBIT  (  BITTree2       n       l       val     *     (  l     -     1  ));      updateBIT  (  BITTree2       n       r     +     1       -  val     *     r  );   }   int     rangeSum  (  int     l       int     r       int     BITTree1  []     int     BITTree2  [])   {      // Find sum from [0r] then subtract sum      // from [0l-1] in order to find sum from      // [lr]      return     sum  (  r       BITTree1       BITTree2  )      -     sum  (  l     -     1       BITTree1       BITTree2  );   }   int  *     constructBITree  (  int     n  )   {      // Create and initialize BITree[] as 0      int  *     BITree     =     new     int  [  n     +     1  ];      for     (  int     i     =     1  ;     i      <=     n  ;     i  ++  )      BITree  [  i  ]     =     0  ;      return     BITree  ;   }   // Driver code   int     main  ()   {      int     n     =     5  ;      // Construct two BIT      int     *  BITTree1       *  BITTree2  ;      // BIT1 to get element at any index      // in the array      BITTree1     =     constructBITree  (  n  );      // BIT 2 maintains the extra term      // which needs to be subtracted      BITTree2     =     constructBITree  (  n  );      // Add 5 to all the elements from [04]      int     l     =     0       r     =     4       val     =     5  ;      updateRange  (  BITTree1       BITTree2       n       val       l       r  );      // Add 10 to all the elements from [24]      l     =     2       r     =     4       val     =     10  ;      updateRange  (  BITTree1       BITTree2       n       val       l       r  );      // Find sum of all the elements from      // [14]      l     =     1       r     =     4  ;      cout      < <     'Sum of elements from ['      < <     l      < <     ''      < <     r       < <     '] is '  ;      cout      < <     rangeSum  (  l       r       BITTree1       BITTree2  )      < <     '  n  '  ;      return     0  ;   }   
Java
   // Java program to demonstrate Range Update   // and Range Queries using BIT   import     java.util.*  ;   class   GFG     {      // Returns sum of arr[0..index]. This function assumes      // that the array is preprocessed and partial sums of      // array elements are stored in BITree[]      static     int     getSum  (  int     BITree  []       int     index  )      {      int     sum     =     0  ;     // Initialize result      // index in BITree[] is 1 more than the index in      // arr[]      index     =     index     +     1  ;      // Traverse ancestors of BITree[index]      while     (  index     >     0  )     {      // Add current element of BITree to sum      sum     +=     BITree  [  index  ]  ;      // Move index to parent node in getSum View      index     -=     index     &     (  -  index  );      }      return     sum  ;      }      // Updates a node in Binary Index Tree (BITree) at given      // index in BITree. The given value 'val' is added to      // BITree[i] and all of its ancestors in tree.      static     void     updateBIT  (  int     BITree  []       int     n       int     index        int     val  )      {      // index in BITree[] is 1 more than the index in      // arr[]      index     =     index     +     1  ;      // Traverse all ancestors and add 'val'      while     (  index      <=     n  )     {      // Add 'val' to current node of BI Tree      BITree  [  index  ]     +=     val  ;      // Update index to that of parent in update View      index     +=     index     &     (  -  index  );      }      }      // Returns the sum of array from [0 x]      static     int     sum  (  int     x       int     BITTree1  []       int     BITTree2  []  )      {      return     (  getSum  (  BITTree1       x  )     *     x  )      -     getSum  (  BITTree2       x  );      }      static     void     updateRange  (  int     BITTree1  []       int     BITTree2  []        int     n       int     val       int     l       int     r  )      {      // Update Both the Binary Index Trees      // As discussed in the article      // Update BIT1      updateBIT  (  BITTree1       n       l       val  );      updateBIT  (  BITTree1       n       r     +     1       -  val  );      // Update BIT2      updateBIT  (  BITTree2       n       l       val     *     (  l     -     1  ));      updateBIT  (  BITTree2       n       r     +     1       -  val     *     r  );      }      static     int     rangeSum  (  int     l       int     r       int     BITTree1  []        int     BITTree2  []  )      {      // Find sum from [0r] then subtract sum      // from [0l-1] in order to find sum from      // [lr]      return     sum  (  r       BITTree1       BITTree2  )      -     sum  (  l     -     1       BITTree1       BITTree2  );      }      static     int  []     constructBITree  (  int     n  )      {      // Create and initialize BITree[] as 0      int  []     BITree     =     new     int  [  n     +     1  ]  ;      for     (  int     i     =     1  ;     i      <=     n  ;     i  ++  )      BITree  [  i  ]     =     0  ;      return     BITree  ;      }      // Driver Program to test above function      public     static     void     main  (  String  []     args  )      {      int     n     =     5  ;      // Contwo BIT      int  []     BITTree1  ;      int  []     BITTree2  ;      // BIT1 to get element at any index      // in the array      BITTree1     =     constructBITree  (  n  );      // BIT 2 maintains the extra term      // which needs to be subtracted      BITTree2     =     constructBITree  (  n  );      // Add 5 to all the elements from [04]      int     l     =     0       r     =     4       val     =     5  ;      updateRange  (  BITTree1       BITTree2       n       val       l       r  );      // Add 10 to all the elements from [24]      l     =     2  ;      r     =     4  ;      val     =     10  ;      updateRange  (  BITTree1       BITTree2       n       val       l       r  );      // Find sum of all the elements from      // [14]      l     =     1  ;      r     =     4  ;      System  .  out  .  print  (  'Sum of elements from ['     +     l     +     ''      +     r     +     '] is '  );      System  .  out  .  print  (  rangeSum  (  l       r       BITTree1       BITTree2  )      +     'n'  );      }   }   // This code is contributed by 29AjayKumar   
Python3
   # Python3 program to demonstrate Range Update   # and Range Queries using BIT   # Returns sum of arr[0..index]. This function assumes   # that the array is preprocessed and partial sums of   # array elements are stored in BITree[]   def   getSum  (  BITree  :   list     index  :   int  )   ->   int  :   summ   =   0   # Initialize result   # index in BITree[] is 1 more than the index in arr[]   index   =   index   +   1   # Traverse ancestors of BITree[index]   while   index   >   0  :   # Add current element of BITree to sum   summ   +=   BITree  [  index  ]   # Move index to parent node in getSum View   index   -=   index   &   (  -  index  )   return   summ   # Updates a node in Binary Index Tree (BITree) at given   # index in BITree. The given value 'val' is added to   # BITree[i] and all of its ancestors in tree.   def   updateBit  (  BITTree  :   list     n  :   int     index  :   int     val  :   int  )   ->   None  :   # index in BITree[] is 1 more than the index in arr[]   index   =   index   +   1   # Traverse all ancestors and add 'val'   while   index    <=   n  :   # Add 'val' to current node of BI Tree   BITTree  [  index  ]   +=   val   # Update index to that of parent in update View   index   +=   index   &   (  -  index  )   # Returns the sum of array from [0 x]   def   summation  (  x  :   int     BITTree1  :   list     BITTree2  :   list  )   ->   int  :   return   (  getSum  (  BITTree1     x  )   *   x  )   -   getSum  (  BITTree2     x  )   def   updateRange  (  BITTree1  :   list     BITTree2  :   list     n  :   int     val  :   int     l  :   int     r  :   int  )   ->   None  :   # Update Both the Binary Index Trees   # As discussed in the article   # Update BIT1   updateBit  (  BITTree1     n     l     val  )   updateBit  (  BITTree1     n     r   +   1     -  val  )   # Update BIT2   updateBit  (  BITTree2     n     l     val   *   (  l   -   1  ))   updateBit  (  BITTree2     n     r   +   1     -  val   *   r  )   def   rangeSum  (  l  :   int     r  :   int     BITTree1  :   list     BITTree2  :   list  )   ->   int  :   # Find sum from [0r] then subtract sum   # from [0l-1] in order to find sum from   # [lr]   return   summation  (  r     BITTree1     BITTree2  )   -   summation  (   l   -   1     BITTree1     BITTree2  )   # Driver Code   if   __name__   ==   '__main__'  :   n   =   5   # BIT1 to get element at any index   # in the array   BITTree1   =   [  0  ]   *   (  n   +   1  )   # BIT 2 maintains the extra term   # which needs to be subtracted   BITTree2   =   [  0  ]   *   (  n   +   1  )   # Add 5 to all the elements from [04]   l   =   0   r   =   4   val   =   5   updateRange  (  BITTree1     BITTree2     n     val     l     r  )   # Add 10 to all the elements from [24]   l   =   2   r   =   4   val   =   10   updateRange  (  BITTree1     BITTree2     n     val     l     r  )   # Find sum of all the elements from   # [14]   l   =   1   r   =   4   print  (  'Sum of elements from [  %d    %d  ] is   %d  '   %   (  l     r     rangeSum  (  l     r     BITTree1     BITTree2  )))   # This code is contributed by   # sanjeev2552   
C#
   // C# program to demonstrate Range Update   // and Range Queries using BIT   using     System  ;   class     GFG     {      // Returns sum of arr[0..index]. This function assumes      // that the array is preprocessed and partial sums of      // array elements are stored in BITree[]      static     int     getSum  (  int  []     BITree       int     index  )      {      int     sum     =     0  ;     // Initialize result      // index in BITree[] is 1 more than      // the index in []arr      index     =     index     +     1  ;      // Traverse ancestors of BITree[index]      while     (  index     >     0  )     {      // Add current element of BITree to sum      sum     +=     BITree  [  index  ];      // Move index to parent node in getSum View      index     -=     index     &     (  -  index  );      }      return     sum  ;      }      // Updates a node in Binary Index Tree (BITree) at given      // index in BITree. The given value 'val' is added to      // BITree[i] and all of its ancestors in tree.      static     void     updateBIT  (  int  []     BITree       int     n       int     index        int     val  )      {      // index in BITree[] is 1 more than      // the index in []arr      index     =     index     +     1  ;      // Traverse all ancestors and add 'val'      while     (  index      <=     n  )     {      // Add 'val' to current node of BI Tree      BITree  [  index  ]     +=     val  ;      // Update index to that of      // parent in update View      index     +=     index     &     (  -  index  );      }      }      // Returns the sum of array from [0 x]      static     int     sum  (  int     x       int  []     BITTree1       int  []     BITTree2  )      {      return     (  getSum  (  BITTree1       x  )     *     x  )      -     getSum  (  BITTree2       x  );      }      static     void     updateRange  (  int  []     BITTree1       int  []     BITTree2        int     n       int     val       int     l       int     r  )      {      // Update Both the Binary Index Trees      // As discussed in the article      // Update BIT1      updateBIT  (  BITTree1       n       l       val  );      updateBIT  (  BITTree1       n       r     +     1       -  val  );      // Update BIT2      updateBIT  (  BITTree2       n       l       val     *     (  l     -     1  ));      updateBIT  (  BITTree2       n       r     +     1       -  val     *     r  );      }      static     int     rangeSum  (  int     l       int     r       int  []     BITTree1        int  []     BITTree2  )      {      // Find sum from [0r] then subtract sum      // from [0l-1] in order to find sum from      // [lr]      return     sum  (  r       BITTree1       BITTree2  )      -     sum  (  l     -     1       BITTree1       BITTree2  );      }      static     int  []     constructBITree  (  int     n  )      {      // Create and initialize BITree[] as 0      int  []     BITree     =     new     int  [  n     +     1  ];      for     (  int     i     =     1  ;     i      <=     n  ;     i  ++  )      BITree  [  i  ]     =     0  ;      return     BITree  ;      }      // Driver Code      public     static     void     Main  (  String  []     args  )      {      int     n     =     5  ;      // Contwo BIT      int  []     BITTree1  ;      int  []     BITTree2  ;      // BIT1 to get element at any index      // in the array      BITTree1     =     constructBITree  (  n  );      // BIT 2 maintains the extra term      // which needs to be subtracted      BITTree2     =     constructBITree  (  n  );      // Add 5 to all the elements from [04]      int     l     =     0       r     =     4       val     =     5  ;      updateRange  (  BITTree1       BITTree2       n       val       l       r  );      // Add 10 to all the elements from [24]      l     =     2  ;      r     =     4  ;      val     =     10  ;      updateRange  (  BITTree1       BITTree2       n       val       l       r  );      // Find sum of all the elements from      // [14]      l     =     1  ;      r     =     4  ;      Console  .  Write  (  'Sum of elements from ['     +     l     +     ''     +     r      +     '] is '  );      Console  .  Write  (  rangeSum  (  l       r       BITTree1       BITTree2  )      +     'n'  );      }   }   // This code is contributed by 29AjayKumar   
JavaScript
    <  script  >   // JavaScript program to demonstrate Range Update   // and Range Queries using BIT   // Returns sum of arr[0..index]. This function assumes   // that the array is preprocessed and partial sums of   // array elements are stored in BITree[]   function     getSum  (  BITree    index  )   {      let     sum     =     0  ;     // Initialize result          // index in BITree[] is 1 more than the index in arr[]      index     =     index     +     1  ;          // Traverse ancestors of BITree[index]      while     (  index     >     0  )      {      // Add current element of BITree to sum      sum     +=     BITree  [  index  ];          // Move index to parent node in getSum View      index     -=     index     &     (  -  index  );      }      return     sum  ;   }   // Updates a node in Binary Index Tree (BITree) at given   // index in BITree. The given value 'val' is added to   // BITree[i] and all of its ancestors in tree.   function     updateBIT  (  BITree    n    index    val  )   {      // index in BITree[] is 1 more than the index in arr[]      index     =     index     +     1  ;          // Traverse all ancestors and add 'val'      while     (  index      <=     n  )      {      // Add 'val' to current node of BI Tree      BITree  [  index  ]     +=     val  ;          // Update index to that of parent in update View      index     +=     index     &     (  -  index  );      }   }   // Returns the sum of array from [0 x]   function     sum  (  x    BITTree1    BITTree2  )   {      return     (  getSum  (  BITTree1       x  )     *     x  )     -     getSum  (  BITTree2       x  );   }   function     updateRange  (  BITTree1    BITTree2    n    val    l    r  )   {      // Update Both the Binary Index Trees      // As discussed in the article          // Update BIT1      updateBIT  (  BITTree1       n       l       val  );      updateBIT  (  BITTree1       n       r     +     1       -  val  );          // Update BIT2      updateBIT  (  BITTree2       n       l       val     *     (  l     -     1  ));      updateBIT  (  BITTree2       n       r     +     1       -  val     *     r  );   }   function     rangeSum  (  l    r    BITTree1    BITTree2  )   {      // Find sum from [0r] then subtract sum      // from [0l-1] in order to find sum from      // [lr]      return     sum  (  r       BITTree1       BITTree2  )     -      sum  (  l     -     1       BITTree1       BITTree2  );   }   function     constructBITree  (  n  )   {      // Create and initialize BITree[] as 0      let     BITree     =     new     Array  (  n     +     1  );      for     (  let     i     =     1  ;     i      <=     n  ;     i  ++  )      BITree  [  i  ]     =     0  ;          return     BITree  ;   }   // Driver Program to test above function   let     n     =     5  ;       // Contwo BIT   let     BITTree1  ;   let     BITTree2  ;   // BIT1 to get element at any index   // in the array   BITTree1     =     constructBITree  (  n  );   // BIT 2 maintains the extra term   // which needs to be subtracted   BITTree2     =     constructBITree  (  n  );   // Add 5 to all the elements from [04]   let     l     =     0          r     =     4          val     =     5  ;   updateRange  (  BITTree1       BITTree2       n       val       l       r  );   // Add 10 to all the elements from [24]   l     =     2     ;     r     =     4     ;     val     =     10  ;   updateRange  (  BITTree1       BITTree2       n       val       l       r  );   // Find sum of all the elements from   // [14]   l     =     1     ;     r     =     4  ;   document  .  write  (  'Sum of elements from ['     +     l      +     ''     +     r  +     '] is '  );   document  .  write  (  rangeSum  (  l       r       BITTree1       BITTree2  )  +     '  
'
); // This code is contributed by rag2127 < /script>

Producción
Sum of elements from [14] is 50 

Complejidad del tiempo : O(q * log(N)) donde q es el número de consultas.
Espacio Auxiliar: EN)