Дерево отрезков. Построение — различия между версиями
Serega (обсуждение | вклад) (→Структура) |
|||
Строка 1: | Строка 1: | ||
− | '''Дерево отрезков''' {{---}} это структура данных, которая позволяет эффективно (за асимптотику <tex | + | '''Дерево отрезков''' {{---}} это структура данных, которая позволяет эффективно (за асимптотику <tex>O(log n))</tex> реализовать операции следующего вида: нахождение суммы (задача RSQ), минимума или максимума (задача RMQ) элементов массива в заданном отрезке (<tex dpi = "140">a[i...j]</tex>, где <tex dpi = "140">i</tex> и <tex dpi = "140">j</tex> поступают на вход алгоритма), при этом дополнительно возможно изменение элементов массива: как изменение значения одного элемента, так и изменение элементов на целом подотрезке массива (т.е. разрешается присвоить всем элементам <tex dpi = "140">a[i...j]</tex> какое-либо значение, либо прибавить ко всем элементам массива какое-либо число). Структура занимает <tex dpi = "140">O(n)</tex> памяти и выстраивается из массива за <tex dpi = "140">O(n)</tex>. |
==Структура== | ==Структура== |
Версия 22:02, 26 апреля 2011
Дерево отрезков — это структура данных, которая позволяет эффективно (за асимптотику
реализовать операции следующего вида: нахождение суммы (задача RSQ), минимума или максимума (задача RMQ) элементов массива в заданном отрезке ( , где и поступают на вход алгоритма), при этом дополнительно возможно изменение элементов массива: как изменение значения одного элемента, так и изменение элементов на целом подотрезке массива (т.е. разрешается присвоить всем элементам какое-либо значение, либо прибавить ко всем элементам массива какое-либо число). Структура занимает памяти и выстраивается из массива за .Структура
Структура представляет собой дерево, листьями которого являются элементы исходного массива. Другие вершины этого дерева имеют по 2 ребёнка и содержат сумму или минимум/максимум своих детей (в зависимости от поставленной задачи). Таким образом, корень содержит результат искомой функции от всего массива , левый ребёнок корня содержит результат функции на , а правый, соответственно результат на . И так далее, продвигаясь вглубь дерева.Построение дерева
Пусть исходный массив
состоит из элементов. Для удобства построения увеличим длину массива так, чтобы она равнялась ближайшей степени двойки, т.е. , где . Это сделано, для того чтобы не допустить обращение к несуществующим элементам массива при дальнейшем процессе построения. Пустые элементы можно заполнить нулями или бесконечностями (за бесконечностью стоит понимать, например, число, больше которого в данных ничего не появится) в зависимости от поставленной задачи. Тогда для хранения дерева отрезков понадобится массив из элементов, поскольку в худшем случае количество вершин в дереве можно оценить суммой , где . Таким образом, структура занимает линейную память.Далее будем считать, что дерево выстраиваем для задачи вычисления суммы на отрезке. Для минимума и максимума операция построения проделывается аналогично.
Процесс построения дерева заключается в заполнении массива
. Заполним этот массив таким образом, чтобы -й элемент являлся бы суммой элемента c номером и элемента с номером , т.е. родитель являлся бы суммой своих сыновей. Лучше всего эту процедуру делать рекурсивно. Создадим функцию от исходного массива , переменной , обозначающей номер элемента в массиве , а так же переменные и , обозначающие соответственно левую и правую границы текущего отрезка. Запускаем процедуру построения от корня дерева отрезков ( , , ), а сама процедура построения, если её вызвали не от листа, вызывает себя от каждого из двух сыновей и суммирует вычисленные значения, а если её вызвали от листа — то просто записывает в себя значение этого элемента массива. Асимптотика построения дерева отрезков составит, таким образом, .Реализация:
TreeBuild(a[], i, tl, tr) if (tl = tr) t[i] = a[tl]; else tm = (tl + tr) / 2; //середина отрезка TreeBuild(a, 2*v, tl, tm); TreeBuild(a, 2*v+1, tm+1, tr); t[v] = t[2*v] + t[2*v+1];
Ссылки
- Визуализатор дерева отрезков