Sumy prefiksowe 2D służą do szybkiego odpowiadania na dużo zapytań o np. sumę na danym prostokącie w prostokątnej tablicy Wymagają preprocessingu (musimy przed ich używaniem je przygotować). UWAGA wartości w tablicy nie mogą ulegać zmianie!
W komórce o indeksach i, j trzymamy sumę na prostokącie o lewym górnym rogu w komórce 1, 1; a prawym dolnym rogu w
komórce i, j. Czyli wartością dla komórki i, j będzie:
sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + tablica[i][j], gdzie tablica to tablica z wartościami w danej komórce
UWAGA w implementacji jako tablicy tablica jest użyta od razu tablica sum. Optymalizuje nam to pamięć.
Wracając do wzoru, to czemu taki jest? sum[i - 1][j] i sum[i][j - 1] załatwiają nam sumę z komórki wyżej i
z komórki po lewej. To jasne że musimy je dodać. Natomiast sum[i - 1][j - 1] odejmujemy, ponieważ dodaliśmy ją 2 razy:
podczas dodawania sum[i - 1][j], sum[i][j - 1]. Możecie sobie tę sytuację narysować, wtedy na pewno lepiej zrozumiecie
🙂. tablica[i][j] dodajemy, ponieważ chcemy mieć sumę łącznie z punktem, który aktualnie rozpatrujemy. To był algorytm
na funkcję wypel (wypełniającą nasze sumy). Ale jak odczytywać wyniki z prostokąta o lewym górnym rogu a, b; a prawym
dolnym c, d? Bardzo prosto - wykorzystujemy wzorek:
sum[c][d] - sum[a - 1][d] - sum[c][b - 1] + sum[a - 1][b - 1];
Czemu jest taki? Zauważmy, że sum[c][d] to jest cały prostokąt 0, 0; c, d;, czyli mamy trochę za dużo. sum[a-1][d] i
sum[c][b - 1] to są indeksy będące na jednej linii z indeksem c, d; ale o 1 poniżej indeksu a, b. Są to więc sumy z
prostokątów nie będących w naszym prostokącie, zawierające się w sum[c][d]. Zauważmy jednak, że sum[a - 1][b - 1]
odjeliśmy 2 razy, więc dodajemy, żeby było odjęte tylko raz.
Zasymuujmy nasze sumy prefiksowe dla takiej tablicy:
1 | 2 |
3 | 1 |
2 | 3 |
1 | 3 |
4 | 7 |
6 | 13 |
W sumach prefiktowych 2D trzeba uważać, czy najpierw podają nam kolumnę czy wiersz komórki. Jest to ważne, bo jeśli tego nie sprawdzimy nasze sumy nie zadziałają.