Задача нахождения суммы элементов массива на интервале, методы её решения
29 ноября 2009 г.
Определение
Часто возникает задача, когда нужно посчитать сумму от i-го до j-го элемента в массиве A.
Формально определим её:
Найти sum =
Рассмотрим как такую задачу решают простым методом.
Методы решения
- Можно каждый раз суммировать элементы с
i
-го поj
-тый
Эффективность такого метода:
Обновление массива:O(1)
Вычисление суммы:O(n)
- Можно завести дополнительный массив частичных сумм
P
, гдеP[1] = A[1], P[i] = P[i-1] + A[i], i>1
И тогда сумма равна:
Sum =
| P[j] – P[i-1] , i>1
| P[j], i=1
Эффективность такого метода:
Обновление массива:O(n)
Вычисление суммы:O(1)
- Оказывается можно объединить эти два метода и получить решение, которое способно обновлять массив и вычислять сумму более эффективно
Этот метод использует дерево Фенвика.
Дерево Фенвика — структура данных, позволяющая быстро изменять значения в массиве и находить некоторые функции от элементов массива. Впервые описано Питером Фенвиком в 1994 году. Дерево Фенвика напоминает дерево отрезков, однако проще в реализации.
Нужно хранить частичные суммы в исходном массиве не от начала до i-го, а от такого элемента, номер которого вычисляется по формуле:i-f(i)+1
.
То естьP[i] = ? A[j], j € (i-f(i);i],
гдеf(i)
– максимальная степень двойки, на которую делитсяi
.
Нетрудно убедиться, чтоf(i)=i?(i & (i?1))
.
Пустьn
— длина массиваA
.
Выберем такое минимальноеk
, что2^k >=n
.
Тогда для хранения дерева Фенвика понадобится массивP
из2^k
элементов. Будем нумеровать их от1
до2k
.
В ячейкеP[i]
будет храниться сумма в ячейках массиваA
сi - f(i) + 1
поi
.
Исходный код для вычисления суммы с 1
по k
for(int i=k;i>0;i-=i&-i)
Sum+=P[i];
Исходный код для увеличения значения t-й ячейки массива A на число x:
for(int i=t;i<=n;i+=i&-i)
P[i]+=x;
В приведенном коде i&-i
и есть то вычисление следующего f(i)
.
В итоге искомая сумма будет равна:
Sum =
| P[j] – P[i-1] , i>1
| P[j], i=1
Эффективность такого метода:
Обновление массива: O(log(n))
Вычисление суммы: O(log(n))
рубрика