Многомерное дерево Фенвика — различия между версиями
Roman (обсуждение | вклад) |
|||
Строка 1: | Строка 1: | ||
{{Определение | {{Определение | ||
|definition= | |definition= | ||
− | '''Многомерное [[дерево Фенвика]]''' - структура данных, требующая <tex> O(n^k) </tex> памяти и позволяющая эффективно (за <tex> O(\log^k n) </tex>) | + | '''Многомерное [[дерево Фенвика]]''' (англ. <i> Multidimensional Binary Indexed Tree</i>) {{---}} структура данных, требующая <tex> O(n^k) </tex> памяти и позволяющая эффективно (за <tex> O(\log^k n) </tex>) |
# изменять значение любого элемента в k-мерном массиве; | # изменять значение любого элемента в k-мерном массиве; | ||
# выполнять некоторую ассоциативную, коммутативную, обратимую операцию <tex> G </tex> на k-мерном прямоугольнике <tex> [i_1, \ldots ,i_k] </tex>;<br/> где n - максимальное значение для каждой координаты. | # выполнять некоторую ассоциативную, коммутативную, обратимую операцию <tex> G </tex> на k-мерном прямоугольнике <tex> [i_1, \ldots ,i_k] </tex>;<br/> где n - максимальное значение для каждой координаты. | ||
}} | }} | ||
− | Рассмотрим дерево Фенвика на примере k-мерного массива с k = 2, | + | Рассмотрим для начала дерево Фенвика на примере k-мерного массива с k = 2, а затем посмотрим, как можно обобщить его на большие размерности. |
Пусть дан массив <tex> A </tex> из <tex> n \times m </tex> элементов: <tex> a_{i,j}</tex>.<br/> | Пусть дан массив <tex> A </tex> из <tex> n \times m </tex> элементов: <tex> a_{i,j}</tex>.<br/> | ||
Строка 17: | Строка 17: | ||
# посчитать количество точек в прямоугольнике <tex>(0, 0), (x, y)</tex>; | # посчитать количество точек в прямоугольнике <tex>(0, 0), (x, y)</tex>; | ||
− | <tex>n</tex> - количество точек, <tex>maxX</tex> - максимальная <tex>X</tex> координата, <tex>maxY</tex> - максимальная <tex>Y</tex> координата.<br/> | + | <tex>n</tex> {{---}} количество точек, <tex>maxX</tex> {{---}} максимальная <tex>X</tex> координата, <tex>maxY</tex> {{---}} максимальная <tex>Y</tex> координата.<br/> |
Тогда дерево строится за <tex>O(n\cdot\log(maxX)\cdot\log(maxY))</tex>, а запросы выполняются за <tex>O(\log (maxX)\cdot\log (maxY))</tex> | Тогда дерево строится за <tex>O(n\cdot\log(maxX)\cdot\log(maxY))</tex>, а запросы выполняются за <tex>O(\log (maxX)\cdot\log (maxY))</tex> | ||
− | Добавляя точку вызовем <tex>inc(x, y, 1)</tex>, а удаляя <tex>inc(x, y, -1)</tex>. Таким образом запрос <tex>sum(x, y)</tex> дает количество точек в прямоугольнике. | + | Добавляя точку вызовем <tex>\mathrm{inc}(x, y, 1)</tex>, а удаляя <tex>\mathrm{inc}(x, y, -1)</tex>. Таким образом запрос <tex>\mathrm{sum}(x, y)</tex> дает количество точек в прямоугольнике. |
− | + | ==Псевдокод== | |
− | + | t {{---}} массив, в котором хранится наше дерево Фенвика. | |
− | <code> | + | <code style = "display: inline-block;"> |
− | + | <font color=green>// </font> | |
− | + | '''int''' sum(x: '''int''', y: '''int'''): | |
− | + | '''int''' result = 0 | |
− | int sum (int | + | '''for''' ('''int''' i = x; i >= 0; i = (i & (i+1)) - 1) |
− | + | '''for''' ('''int''' j = y; j >= 0; j = (j & (j+1)) - 1) | |
− | int result = 0 | + | result += t[i][j]; |
− | for (int i = x; i >= 0; i = (i & (i+1)) - 1) | + | '''return''' result; |
− | + | </code> | |
− | + | <code style = "display: inline-block;"> | |
− | return result; | + | '''func''' inc(x: '''int''', y: '''int''', delta: '''int'''): |
− | + | '''for''' ('''int''' i = x; i < maxX; i = (i | (i+1))) | |
− | + | '''for''' ('''int''' j = y; j < maxY; j = (j | (j+1))) | |
− | + | t[i][j] += delta; | |
− | |||
− | for (int i = x; i < | ||
− | |||
− | |||
} | } | ||
</code> | </code> | ||
− | Чтобы посчитать значение функции для прямоугольника <tex>(x_1, y_1), (x_2, y_2)</tex> нужно воспользоваться формулой включения-исключения. Например для суммы: <tex>s = sum(x_2,y_2)-sum(x_2,y_1 - 1)-sum(x_1 - 1,y_2)+sum(x_1 - 1,y_1 - 1)</tex><br/> | + | Чтобы посчитать значение функции для прямоугольника <tex>(x_1, y_1), (x_2, y_2)</tex> нужно воспользоваться формулой [[Формула включения-исключения|включения-исключения]]. Например, для суммы: <tex>s = \mathrm{sum}(x_2,y_2)-\mathrm{sum}(x_2,y_1 - 1)-\mathrm{sum}(x_1 - 1,y_2)+\mathrm{sum}(x_1 - 1,y_1 - 1)</tex><br/> |
[[Файл:ФормулаВключения-Исключения.jpg]] | [[Файл:ФормулаВключения-Исключения.jpg]] | ||
+ | ==Обобщение на большие размерности== | ||
+ | Чтобы увеличить размерность дерева Фенвика, нам достаточно во всех операциях для каждой новой размерности просто добавить вложенный цикл, пробегающий в ней соответствующие индексы. | ||
+ | ==См. также== | ||
+ | *[http://e-maxx.ru/algo/fenwick_tree Дерево Фенвика] | ||
− | == | + | ==Источники информации== |
− | + | *[https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/ Binary Indexed Trees] | |
− | |||
− |
Версия 00:45, 5 июня 2015
Определение: |
Многомерное дерево Фенвика (англ. Multidimensional Binary Indexed Tree) — структура данных, требующая памяти и позволяющая эффективно (за )
|
Рассмотрим для начала дерево Фенвика на примере k-мерного массива с k = 2, а затем посмотрим, как можно обобщить его на большие размерности.
Пусть дан массив
Деревом Фенвика будем называть массив из элементов: , где , как и в одномерном дереве Фенвика.
Содержание
Пример задачи для двумерного случая
Пусть имеем набор точек на плоскости с неотрицательными координатами. Определены 3 операции:
- добавить точку в ;
- удалить точку из ;
- посчитать количество точек в прямоугольнике ;
Тогда дерево строится за , а запросы выполняются за
Добавляя точку вызовем
, а удаляя . Таким образом запрос дает количество точек в прямоугольнике.Псевдокод
t — массив, в котором хранится наше дерево Фенвика.
//
int sum(x: int, y: int): int result = 0 for (int i = x; i >= 0; i = (i & (i+1)) - 1) for (int j = y; j >= 0; j = (j & (j+1)) - 1) result += t[i][j]; return result;
func inc(x: int, y: int, delta: int): for (int i = x; i < maxX; i = (i | (i+1))) for (int j = y; j < maxY; j = (j | (j+1))) t[i][j] += delta; }
Чтобы посчитать значение функции для прямоугольника включения-исключения. Например, для суммы:
Обобщение на большие размерности
Чтобы увеличить размерность дерева Фенвика, нам достаточно во всех операциях для каждой новой размерности просто добавить вложенный цикл, пробегающий в ней соответствующие индексы.