Binäärinen indeksoitu puu: Aluepäivitys ja aluekyselyt

Annettu taulukko arr[0..N-1]. Seuraavat toiminnot on suoritettava. 

  1. päivitys (l r val) : Lisää "val" kaikkiin taulukon elementteihin alkaen [l r].
  2. getRangeSum(l r) : Etsi taulukon kaikkien elementtien summa [l r]:sta.

Aluksi kaikki taulukon elementit ovat 0. Kyselyt voivat olla missä tahansa järjestyksessä, eli päivityksiä voi olla useita ennen alueen summaa.

Esimerkki:

Syöte: N = 5  // {0 0 0 0 0}
Kyselyt: päivitys: l = 0 r = 4 val = 2
               päivitys: l = 3 r = 4 val = 3 
               getRangeSum : l = 2 r = 4

Lähtö: Alueen [2 4] alkioiden summa on 12
Selitys: Ensimmäisen päivityksen jälkeen taulukosta tulee {2 2 2 2 2}
Toisen päivityksen jälkeen taulukosta tulee {2 2 2 5 5}

Naiivi lähestymistapa: Ratkaise ongelma noudattamalla alla olevaa ideaa:

Vuonna edellinen postaus keskustelimme alueen päivitys- ja pistekyselyratkaisuista BIT:n avulla. 
rangeUpdate(l r val) : Lisäämme 'val' -elementtiin indeksissä 'l'. Vähennämme 'val' elementistä indeksissä 'r+1'. 
getElement(index) [tai getSum()]: Palautamme elementtien summan 0:sta indeksiin, joka saadaan nopeasti BIT:n avulla.
Voimme laskea rangeSum() käyttämällä getSum()-kyselyjä. 
rangeSum(l r) = getSum(r) - getSum(l-1)

Yksinkertainen ratkaisu on käyttää kohdassa käsiteltyjä ratkaisuja edellinen postaus . Alueen päivityskysely on sama. Alueen summakysely voidaan saavuttaa tekemällä hakukysely kaikille alueen elementeille. 

Tehokas lähestymistapa: Ratkaise ongelma noudattamalla alla olevaa ideaa:

Saamme alueen summan käyttämällä etuliitesummia. Kuinka varmistaa, että päivitys tehdään niin, että etuliitesumma voidaan tehdä nopeasti? Tarkastellaan tilannetta, jossa etuliitesumma [0 k] (missä 0 <= k < n) is needed after range update on the range [l r]. Three cases arise as k can possibly lie in 3 regions.

  • Tapaus 1 : 0 < k < l 
    • Päivityskysely ei vaikuta summakyselyyn.
  • Tapaus 2 : l <= k <= r 
    • Harkitse esimerkkiä:  Lisää 2 alueelle [2 4], tuloksena oleva taulukko olisi: 0 0 2 2 2
      Jos k = 3 Summa arvosta [0 k] = 4

Kuinka saada tämä tulos? 
Lisää vain val l:stä th indeksi k th indeksi. Summaa kasvatetaan arvolla 'val*(k) - val*(l-1)' päivityskyselyn jälkeen. 

  • Tapaus 3 : k > r 
    • Tässä tapauksessa meidän on lisättävä "val" l:stä th indeksi r th indeksi. Summaa kasvatetaan arvolla 'val*r – val*(l-1)' päivityskyselyn vuoksi.

Havainnot:  

Tapaus 1: on yksinkertainen, koska summa pysyisi samana kuin se oli ennen päivitystä.

Tapaus 2: Summaa kasvatettiin arvolla val*k - val*(l-1). Voimme löytää 'val', se on samanlainen kuin i:n löytäminen th elementti sisään alueen päivitys ja pistekyselyartikkeli . Ylläpidämme siis yhtä bittiä alueen päivitykselle ja pistekyselyille, tämä BIT auttaa löytämään arvon k:stä th indeksi. Nyt val * k lasketaan kuinka käsitellä ylimääräistä termiä val*(l-1)? 
Tämän ylimääräisen termin käsittelemiseksi ylläpidämme toista BIT:tä (BIT2). Päivitä val * (l-1) klo l th indeksi, joten kun getSum-kysely suoritetaan BIT2:lle, tulos on val*(l-1).

Tapaus 3: Summaa tapauksessa 3 kasvatettiin arvolla 'val*r - val *(l-1)', tämän termin arvo voidaan saada käyttämällä BIT2:ta. Lisäämisen sijaan vähennämme 'val*(l-1) - val*r', koska saamme tämän arvon BIT2:sta lisäämällä val*(l-1), kuten teimme tapauksessa 2 ja vähentämällä val*r jokaisessa päivitysoperaatiossa.

Päivitä kysely 

Päivitys (BITree1 l val)
Päivitys (BITree1 r+1 -val)
PäivitysBIT2(BITree2 l val*(l-1))
PäivitäBIT2(BITree2 r+1 -val*r)

Alueen summa 

getSum(BITTree1 k) *k) - getSum(BITTree2 k)

Ratkaise ongelma noudattamalla alla olevia ohjeita:

  • Luo kaksi binaarista indeksipuuta käyttämällä annettua funktiota constructBITree()
  • Jos haluat löytää summan tietyltä alueelta, kutsu funktio rangeSum() parametreilla annettuna alueena ja binaariin indeksoidut puut
    • Kutsu funktion summa, joka palauttaa summan alueella [0 X]
    • Paluusumma(R) - summa(L-1)
      • Kutsu tämän funktion sisällä funktio getSum(), joka palauttaa taulukon summan arvosta [0 X]
      • Palauttaa getSum(Puu1 x) * x - getSum(puu2 x)
      • Luo getSum()-funktion sisällä kokonaislukusumma, joka on yhtä suuri kuin nolla ja suurenna indeksiä yhdellä
      • Kun indeksi on suurempi kuin nolla, lisää summaa Tree[index]
      • Pienennä indeksiä (indeksi & (-indeksi)) siirtääksesi hakemiston puun pääsolmuun
      • Palautussumma
  • Tulosta summa annetulla alueella

Alla on yllä olevan lähestymistavan toteutus: 

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>

Lähtö
Sum of elements from [14] is 50 

Aika monimutkaisuus : O(q * log(N)) missä q on kyselyjen lukumäärä.
Aputila: O(N)