Теоретический материал

Изменение k-го элемента массива A -- update(k, d )

При изменении k-го элемента массива A необходимо соответствующим образом изменить элементы массива B, в определении которых частичные суммы содержат элемент Ak. То есть для выполнения операции update(k, d ) (прибавления к k-му элементу массива A числа d) нужно прибавить d к тем элементам Bj массива B, для которых f (j)$ \le$k$ \le$j.

Утверждается, что все такие j, и только они, являются элементами последовательности k0, k1, k2, ..., km, где k0 = k, ki + 1 = ki | (ki + 1), km + 1 = km | (km + 1) > N - 1. Под | имеется в виду операция побитового ИЛИ.

\epsfbox{fenwick/fenwick04.eps}

Рис. 4.

Сначала покажем, что указанная последовательность строго возрастает, и ее длина составляет порядка O(log N) в худшем случае. Для этого рассмотрим двоичное представление числа ki (рис. 4). Число ki + 1 получается из ki заменой младшего нулевого бита на единичный. Таким образом, ki + 1 > ki, а длина последовательности m заведомо не превосходит количества бит в двоичном представлении числа N.

N - 1 92 10111002
k0 = k 73 10010012
k1 75 10010112
k2=km 79 10011112
k3 95 10111112

 

 

 

 

 

Рис. 5.

На рис. 5 приведен пример указанной последовательности для N = 93 и k = 73.

Покажем, почему элементы последовательности являются индексами тех и только тех элементов массива B, которые нужно изменить при операции update(k, d ).

j X0... k
k Y1... k

Рис. 6.

Поскольку при увеличении номера элемента последовательности, количество единичных битов на конце ki возрастает, то f (ki) убывает. Учитывая еще и то, что сама последовательность ki возрастает, получаем:

f (km) <...< f (k2) < f (k1) < f (k0)$\displaystyle \le$k = k0 < k1 < k2 <...< km

Таким образом, все элементы нашей последовательности являются индексами тех элементов массива B, которые надо изменить.

Покажем, что других элементов, которые надо изменить, нет. Предположим, что есть некоторый индекс j, не лежащий в нашей последовательности, такой что f (j)$ \le$k$ \le$j.

Рассмотрим младший бит, в котором у j стоит 0, а у k стоит 1 -- такой существует, поскольку j не встречается в последовательности ki. Обозначим числа, образованные более старшими битами чисел j и k, через X и Y соответственно. Если X > Y, то j$ \ge$f (j)$ \ge$X0...02 > k, а стало быть, частичная сумма Bj не содержит элемента Ak. Если же X$ \le$Y, то k > j$ \ge$f (j) и опять же частичная сумма Bj не содержит элемента Ak. Значит, индексы всех элементов массива B, которые надо изменить присутствуют в последовательности ki.

Ниже приводится текст подпрограммы, реализующий операцию изменения update(k, d):

 1: Procedure update(k, d : LongInt);
2: begin
3: while (k < N) do begin
4: inc(B[k], d);
5: k := k or (k + 1);
6: end;
7: end;

В силу того, что длина последовательности ki составляет O(log N) в худшем случае, количество итераций цикла while в строках 3-6, а значит, и время работы процедуры update(k, d), составляет O(log N).