Предположим, у вас был пустой массив:
0 0 0 0 0 0 0 0 0 0 (array)
0 0 0 0 0 0 0 0 0 0 (cumulative sums)
И вы хотели обновить диапазон от +5 до [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)
Как вы можете хранить желаемые совокупные суммы, используя 2 дерева с двоичными индексами?
Хитрость заключается в том, чтобы использовать два дерева с двоичными индексами, BIT1 и BIT2, где совокупная сумма рассчитывается по их содержанию. В этом примере вот что мы будем хранить в двух деревьях:
0 0 0 5 5 5 5 5 0 0 (BIT1)
0 0 0 10 10 10 10 10 -25 -25 (BIT2)
Чтобы найти sum[i]
, вы рассчитываете это:
sum[i] = BIT1[i] * i - BIT2[i]
Например:
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
Чтобы достичь желаемых значений BIT1 и BIT2 для предыдущего обновления диапазона, мы делаем 3 обновления диапазона:
Нам нужно обновить диапазон +5 до индексов 3..7 для BIT1.
Нам нужно обновить диапазон +10 до индексов 3..7 для BIT2.
Нам нужно обновить диапазон от -25 до индексов 8..9 для BIT2.
Теперь давайте сделаем еще одно преобразование. Вместо того, чтобы хранить значения, показанные выше для BIT1 и BIT2, мы фактически сохраняем их кумулятивные суммы. Это позволяет нам выполнить 3 обновления диапазона выше, выполнив 4 обновления кумулятивных сумм:
BIT1sum[3] += 5
BIT1sum[8] -= 5
BIT2sum[3] += 10
BIT2sum[8] -= 35
В общем случае алгоритм добавления значения v в диапазон [i..j] будет выглядеть так:
BIT1sum[i] += v
BIT1sum[j+1] -= v
BIT2sum[i] += v * (i-1)
BIT2sum[j+1] -= v * j
где синтаксис + = и - = просто означает обновление структуры данных накопленной суммы BIT с положительным или отрицательным значением в этом индексе. Обратите внимание, что когда вы обновляете совокупную сумму BIT по индексу, она неявно влияет на все индексы справа от этого индекса. Например:
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])
O ( журналн )
sum[i] = BIT1[i] * i - BIT2[i]
? Кажется, что это работает, но это кажется настолько произвольным ... какое понимание позволяет вам прийти к этому?