Дерево Фенвика с модификацией на отрезке: различия между версиями
Ctrlalt (обсуждение | вклад) |
Ctrlalt (обсуждение | вклад) Нет описания правки |
||
Строка 1: | Строка 1: | ||
Переименуем функцию <tt>sum()</tt> в функцию <tt>alpha()</tt>, а функцию <tt>add()</tt> — в функцию <tt>modifyAlphas()</tt>. | |||
int alpha(int r) { | |||
int res = 0; | |||
for (int i = r; i >= 0; i = (i & (i + 1)) - 1) | |||
res += b[i]; | |||
return res; | |||
} | |||
void modifyAlphas(int pos, int val) { | |||
for (int i = pos; i < MAX_SIZE; i |= i + 1) | |||
b[i] += val; | |||
} | |||
Тогда в общем случае мы можем считать, что вызов <tt>alpha(i)</tt> возвращает результат некоторой функции <tt>α(i)</tt> (или элемент некоторого массива <tt>α[i]</tt>), а вызов <tt>modifyAlphas(pos, val)</tt> добавляет значение <tt>val</tt> ко всем <tt>α(i)</tt> (или <tt>α[i]</tt>), у которых <tt>i >= pos</tt>. | |||
В зависимости от того, как трактовать значение <tt>α(i)</tt>, можно получить несколько применений дерева Фенвика. | |||
Если считать, что <tt>α(i)</tt> — сумма элементов массива <tt>a[]</tt> от <tt>a[0]</tt> до <tt>a[i]</tt>, то мы получим базовую версию дерева Фенвика, в которой функция <tt>modifyAlphas()</tt> изменяет элемент массива <tt>a[]</tt>. | |||
== Запрос отдельных элементов и модификация на отрезке == | == Запрос отдельных элементов и модификация на отрезке == | ||
Пусть <tt>α(i)</tt> — значение <tt>i</tt>-го элемента массива <tt>a[]</tt>. Тогда вызов <tt>modifyAlphas(pos, val)</tt> добавит <tt>val</tt> ко всем элементам <tt>a[]</tt>, у которых <tt>i >= pos</tt>. Следовательно, чтобы увеличить только элементы с индексами от <tt>l</tt> до <tt>r</tt>, нужно вызвать <tt>modifyAlphas(l, val)</tt> и <tt>modifyAlphas(r + 1, -val)</tt>. | |||
int get(int pos) { | |||
return alpha(pos); | |||
} | |||
int add(int l, int r, int val) { | |||
modifyAlphas(l, val); | |||
modifyAlphas(r + 1, -val); | |||
} | |||
== Запрос на отрезке и модификация на отрезке == | == Запрос на отрезке и модификация на отрезке == | ||
Пусть используется второе дерево Фенвика, реализующее функции <tt>beta()</tt> и <tt>modifyBetas()</tt>, и пусть <tt>(β(i) * i + α(i))</tt> — сумма элементов массива <tt>a[]</tt> от <tt>a[0]</tt> до <tt>a[i]</tt>. | |||
Далее, пусть элементы массива <tt>a[]</tt> с индексами от <tt>l</tt> до <tt>r</tt> увеличились на величину <tt>val</tt>. Рассмотрим, как при этом изменится сумма элементов массива <tt>a[]</tt> от <tt>a[0]</tt> до <tt>a[i]</tt>: | |||
* Если <tt> | * Если <tt>i < l</tt>, то сумма не изменилась, и значение <tt>(β(i) * i + α(i))</tt> ей соответствует. | ||
* Если <tt>l <= | * Если <tt>l <= i <= r</tt>, то сумма увеличилась на <tt>(val * (i - l + 1))</tt>. Следовательно, к <tt>β(i)</tt> нужно добавить <tt>val</tt>, а к <tt>α(i)</tt> — <tt>(val * (-l + 1))</tt>. | ||
* Если <tt>r | * Если <tt>i > r</tt>, то сумма увеличилась на <tt>(val * (r - l + 1))</tt>. Следовательно, <tt>β(i)</tt> изменять не нужно, а к <tt>α(i)</tt> нужно добавить <tt>(val * (r - l + 1))</tt>. | ||
int sum(int r) { | |||
* | return beta(r) * r + alpha(r); | ||
} | |||
void add(int l, int r, int val) { | |||
modifyBetas(l, val); | |||
modifyAlphas(l, val * (-l + 1)); | |||
modifyBetas(r + 1, -val); //modifyBetas(r + 1, 0 - val); | |||
modifyAlphas(r + 1, val * r); //modifyAlphas(r + 1, (val * (r - l + 1)) - (val * (-l + 1))); | |||
} | |||
== Ссылки == | == Ссылки == | ||
* [http://petr-mitrichev.blogspot.ru/2013/05/fenwick-tree-range-updates.html petr-mitrichev.blogspot.ru — Fenwick tree range updates] | |||
* [http://apps.topcoder.com/forums/?module=Thread&threadID=756271 topcoder.com — How to modify BIT to update the ranges and query the ranges?] | * [http://apps.topcoder.com/forums/?module=Thread&threadID=756271 topcoder.com — How to modify BIT to update the ranges and query the ranges?] | ||
* [http://apps.topcoder.com/forums/?module=Thread&threadID=715842 topcoder.com — Range update in BIT] | * [http://apps.topcoder.com/forums/?module=Thread&threadID=715842 topcoder.com — Range update in BIT] |
Версия от 02:03, 14 ноября 2014
Переименуем функцию sum() в функцию alpha(), а функцию add() — в функцию modifyAlphas().
int alpha(int r) { int res = 0; for (int i = r; i >= 0; i = (i & (i + 1)) - 1) res += b[i]; return res; } void modifyAlphas(int pos, int val) { for (int i = pos; i < MAX_SIZE; i |= i + 1) b[i] += val; }
Тогда в общем случае мы можем считать, что вызов alpha(i) возвращает результат некоторой функции α(i) (или элемент некоторого массива α[i]), а вызов modifyAlphas(pos, val) добавляет значение val ко всем α(i) (или α[i]), у которых i >= pos. В зависимости от того, как трактовать значение α(i), можно получить несколько применений дерева Фенвика. Если считать, что α(i) — сумма элементов массива a[] от a[0] до a[i], то мы получим базовую версию дерева Фенвика, в которой функция modifyAlphas() изменяет элемент массива a[].
Запрос отдельных элементов и модификация на отрезке
Пусть α(i) — значение i-го элемента массива a[]. Тогда вызов modifyAlphas(pos, val) добавит val ко всем элементам a[], у которых i >= pos. Следовательно, чтобы увеличить только элементы с индексами от l до r, нужно вызвать modifyAlphas(l, val) и modifyAlphas(r + 1, -val).
int get(int pos) { return alpha(pos); } int add(int l, int r, int val) { modifyAlphas(l, val); modifyAlphas(r + 1, -val); }
Запрос на отрезке и модификация на отрезке
Пусть используется второе дерево Фенвика, реализующее функции beta() и modifyBetas(), и пусть (β(i) * i + α(i)) — сумма элементов массива a[] от a[0] до a[i]. Далее, пусть элементы массива a[] с индексами от l до r увеличились на величину val. Рассмотрим, как при этом изменится сумма элементов массива a[] от a[0] до a[i]:
- Если i < l, то сумма не изменилась, и значение (β(i) * i + α(i)) ей соответствует.
- Если l <= i <= r, то сумма увеличилась на (val * (i - l + 1)). Следовательно, к β(i) нужно добавить val, а к α(i) — (val * (-l + 1)).
- Если i > r, то сумма увеличилась на (val * (r - l + 1)). Следовательно, β(i) изменять не нужно, а к α(i) нужно добавить (val * (r - l + 1)).
int sum(int r) { return beta(r) * r + alpha(r); } void add(int l, int r, int val) { modifyBetas(l, val); modifyAlphas(l, val * (-l + 1)); modifyBetas(r + 1, -val); //modifyBetas(r + 1, 0 - val); modifyAlphas(r + 1, val * r); //modifyAlphas(r + 1, (val * (r - l + 1)) - (val * (-l + 1))); }