Aggiornamento intervallo + query intervallo con alberi indicizzati binari


10

Sto cercando di capire come gli alberi indicizzati binari (alberi fenwick) possano essere modificati per gestire sia le query di intervallo sia gli aggiornamenti di intervallo.

Ho trovato le seguenti fonti:

http://kartikkukreja.wordpress.com/2013/12/02/range-updates-with-bit-fenwick-tree/ http://programmingcontests.quora.com/Tutorial-Range-Updates-in-Fenwick-Tree http :? //apps.topcoder.com/forums/ module = thread & threadID = 756.271 & start = 0 & mc = 4 # 1.579.597

Ma anche dopo aver letto tutti loro non sono riuscito a capire quale sia lo scopo del secondo albero indicizzato binario o cosa faccia.

Qualcuno potrebbe spiegarmi come viene modificato l'albero indicizzato binario per gestirli?

Risposte:


9

Supponiamo di avere un array vuoto:

0  0  0  0  0  0  0  0  0  0  (array)
0  0  0  0  0  0  0  0  0  0  (cumulative sums)

E volevi fare un aggiornamento della gamma da +5 a [3..7]:

0  0  0  5  5  5  5  5  0  0  (array)
0  0  0  5 10 15 20 25 25 25  (desired cumulative sums)

Come è possibile memorizzare le somme cumulative desiderate utilizzando 2 alberi indicizzati binari?

Il trucco è utilizzare due alberi binari indicizzati, BIT1 e BIT2, in cui la somma cumulativa viene calcolata dal loro contenuto. In questo esempio, ecco cosa memorizzeremmo nei due alberi:

0   0   0   5   5   5   5   5   0   0  (BIT1)
0   0   0  10  10  10  10  10 -25 -25  (BIT2)

Per trovare sum[i], calcola questo:

sum[i] = BIT1[i] * i - BIT2[i]

Per esempio:

sum[2] = 0*2 - 0 = 0
sum[3] = 5*3 - 10 = 5
sum[4] = 5*4 - 10 = 10
...
sum[7] = 5*7 - 10 = 25
sum[8] = 0*8 - (-25) = 25
sum[9] = 0*9 - (-25) = 25

Per ottenere i valori BIT1 e BIT2 desiderati per l'aggiornamento di intervallo precedente, eseguiamo 3 aggiornamenti di intervallo:

  • Dobbiamo fare un aggiornamento di intervallo di +5 agli indici 3..7 per BIT1.

  • Dobbiamo fare un aggiornamento di intervallo di +10 agli indici 3..7 per BIT2.

  • Dobbiamo fare un aggiornamento di intervallo da -25 agli indici 8..9 per BIT2.

Ora facciamo un'altra trasformazione. Invece di memorizzare i valori mostrati sopra per BIT1 e BIT2, archiviamo effettivamente le loro somme cumulative. Questo ci consente di effettuare i 3 aggiornamenti di intervallo sopra apportando 4 aggiornamenti alle somme cumulative:

BIT1sum[3] += 5
BIT1sum[8] -= 5
BIT2sum[3] += 10
BIT2sum[8] -= 35

In generale, l'algoritmo per aggiungere un valore v a un intervallo [i..j] sarebbe:

BIT1sum[i]   += v
BIT1sum[j+1] -= v
BIT2sum[i]   += v * (i-1)
BIT2sum[j+1] -= v * j

dove la sintassi + = e - = significa semplicemente aggiornare la struttura dei dati della somma cumulativa BIT con un valore positivo o negativo in quell'indice. Si noti che quando si aggiorna la somma cumulativa BIT in un indice, ciò influisce implicitamente su tutti gli indici a destra di tale indice. Per esempio:

0 0 0 0 0 0 0 0 0 0 (original)

BITsum[3] += 5

0 0 0 5 5 5 5 5 5 5 (after updating [3])

BITsum[8] -= 5

0 0 0 5 5 5 5 5 0 0 (after updating [8])

Gli alberi di Fenwick immagazzinano somme in un albero binario. È facile eseguire gli aggiornamenti mostrati sopra su un albero Fenwick, in tempo .O(logn)


Qual è stata la tua motivazione iniziale nella creazione di BIT2 e successivamente sum[i] = BIT1[i] * i - BIT2[i]? Sembra funzionare ma sembra così arbitrario ... quale intuizione ti permette di arrivare a questo?
1110101001,

3
Beh, non ho inventato questo algoritmo. L'ho letto proprio come hai fatto tu. Ma una cosa da notare è che quando si aggiunge un aggiornamento di intervallo, le somme cumulative diventano una sequenza crescente (5, 10, 15, 20, ...). I BIT non memorizzano sequenze crescenti del genere. Ma se memorizzi una costante (5) nel BIT e moltiplichi il valore del BIT per l'indice, otterrai una sequenza crescente proprio come quella che desideri. Tuttavia, è necessario correggere l'inizio e la fine della sequenza. Ecco a cosa serve il secondo albero.
JS1

Buono nel complesso, ma ho trovato confuso che tu abbia scritto "Invece di memorizzare i valori mostrati sopra per BIT1 e BIT2, in realtà memorizziamo le loro somme cumulative" - ​​Direi che stai effettivamente facendo il contrario, cioè archiviando i delta .
j_random_hacker,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.