72
правки
Изменения
Нет необходимости рассматривать пустой полуинтервал
'''Дерево отрезков''' (англ. ''Segment tree'') {{---}} это структура данных, которая позволяет за асимптотику <tex>O(\log n)</tex> реализовать любые операции, определяемые на множестве, на котором данная операция ассоциативна, и существует нейтральный элемент относительно этой операции, то есть на [[Моноид | моноиде]]. Например, следующего вида: нахождение суммы (задача RSQ)суммирование на множестве натуральных чисел, поиск минимума или максимума (задача RMQ) элементов массива в заданном отрезке (на любом числовом множестве, перемножение матриц на множестве матриц размера <tex>a[l...r]N*N</tex>, где <tex>l</tex> объединение множеств, поиск наибольшего общего делителя на множестве целых чисел и <tex>r</tex> поступают на вход алгоритма)многочленов.
При этом дополнительно возможно изменение элементов массива: как изменение значения одного элемента, так и [[Несогласованные поддеревья. Реализация массового обновления | изменение элементов на целом подотрезке массива]], например разрешается присвоить всем элементам <tex>a[l...\ldots r]</tex> какое-либо значение, либо прибавить ко всем элементам массива какое-либо число. Структура занимает <tex>O(n)</tex> памяти, а ее построение требует <tex>O(n)</tex> времени.
==Структура==
Структура представляет собой дерево, листьями которого являются элементы исходного массива. Другие вершины этого дерева имеют по <tex>2 </tex> ребенка и содержат результат операции от своих детей (например минимум или сумму). Таким образом, корень содержит результат искомой функции от всего массива <tex>[0...\ldots n-1]</tex>, левый ребёнок корня содержит результат функции на <tex dpi=120>[0...\fracldots\dfrac{n}{2}]</tex>, а правый, соответственно результат на <tex dpi=120>[\fracdfrac{n}{2}+1...\ldots n-1]</tex>. И так далее, продвигаясь вглубь дерева.
==Построение дерева==
Пусть исходный массив <tex>a</tex> состоит из <tex>n</tex> элементов. Для удобства построения увеличим длину массива <tex>a</tex> так, чтобы она равнялась ближайшей степени двойки, т.е. <tex>2^k</tex>, где <tex>2^k \ge geqslant n</tex>. Это сделано, для того чтобы не допустить обращение к несуществующим элементам массива при дальнейшем процессе построения. Пустые элементы необходимо заполнить нейтральными элементами моноида. Тогда для хранения дерева отрезков понадобится массив <tex>t</tex> из <tex>2^{k+1}</tex> элементов, поскольку в худшем случае количество вершин в дереве можно оценить суммой <tex>n+\fracdfrac{n}{2}+\fracdfrac{n}{4}...\ldots +1 < 2n</tex>, где <tex>n=2^k</tex>. Таким образом, структура занимает линейную память.
Процесс построения дерева заключается в заполнении массива <tex>t</tex>. Заполним этот массив таким образом, чтобы <tex>i</tex>-й элемент являлся бы результатом некоторой бинарной операции (для каждой конкретной задачи своей) от элементов c номерами <tex>2i+1</tex> и <tex>2i+2</tex>, то есть родитель являлся результатом бинарной операции от своих сыновей(обозначим в коде эту операцию как "<tex> \circ </tex>"). Один из вариантов — делать рекурсивно. Пусть у нас имеются исходный массив <tex>a</tex>, а также переменные <tex>\mathtt{tl}</tex> и <tex>\mathtt{tr}</tex>, обозначающие границы текущего полуинтервала. Запускаем процедуру построения от корня дерева отрезков (<tex>i=0</tex>, <tex>\mathtt{tl}=0</tex>, <tex>\mathtt{tr}=n</tex>), а сама процедура построения, если её вызвали не от листа, вызывает себя от каждого из двух сыновей и суммирует вычисленные значения, а если её вызвали от листа — то просто записывает в себя значение этого элемента массива (Для этого у нас есть исходный массив <tex> a </tex>). Асимптотика построения дерева отрезков составит, таким образом, <tex>O(n)</tex>.
Выделяют два основных способа построения дерева отрезков: построение снизу и построение сверху. При построении [[Реализация запроса в дереве отрезков снизу | снизу]] алгоритм поднимается от листьев к корню (Просто начинаем заполнять элементы массива <tex>t</tex> от большего индекса к меньшему, таким образом при заполнении элемента <tex> i </tex> его дети <tex>2i+1</tex> и <tex>2i+2</tex> уже будут заполнены, и мы с легкостью посчитаем бинарную операцию от них), а при построении [[Реализация запроса в дереве отрезков сверху | сверху]] спускается от корня к листьям. Особенные изменения появляются в реализации запросов к таким деревьям отрезков.
[[Файл:Segment_tree.png|Пример дерева отрезков для максимумаминимума]]
Реализация построения сверху:
'''function''' treeBuild('''T''' a[], '''int''' i, '''int''' tl, '''int''' tr): <font color=green>// Мы мы находимся в вершине с номером i, который отвечает за полуинтервал [tl, tr) '''if''' tl == tr </font> '''return''' '''if''' tr - tl == 1 t[i] = a[tl] '''else''' tm = (tl + tr) / 2 <font color=green>//середина отрезка</font> TreeBuild treeBuild(a, 2 * i + 1, tl, tm) TreeBuild treeBuild(a, 2 * i + 2, tm, tr) t[i] = t[2 * i + 1] <tex> \circ </tex> t[2 * i + 2]
Реализация построения снизу:
'''function''' treeBuild('''T''' a[]): '''for''' i = 0 '''to''' n - 1 .. 2 * t[n - 1 t[+ i] = a[i - n - 1] '''for''' i = n - 2 .. '''downto''' 0 t[i] = t[2 * i + 1] <tex> \circ </tex> t[2 * i + 2]
==Персистентное дерево отрезков=={{Определение|definition='''Персистентной''' (англСм. ''Persistent'') называется такая структура данных, которая хранит все свои промежуточные версии.}}{{Определение|definition='''Полностью персистентной''' (англ. ''Fully persistent'') называется такая персистентная структура данных, в которой разрешено изменять любую её версию и делать запросы к любой её версии.}}На основе дерева отрезков можно построить полностью персистентную структуру данных. ===Структура дерева=также==Для реализации персистентного дерева отрезков удобно несколько изменить структуру дерева. Для этого будем использовать явные указатели <tex>L</tex> и <tex>R</tex> для дочерних элементов. Кроме того, заведем массив <tex>roots* [[]</tex>, Реализация запроса в котором <tex>roots[iдереве отрезков сверху]</tex> указывает на корень дерева отрезков версии <tex>i</tex> ===Построение===Для построения персистентного дерева отрезков из <tex>n</tex> элементов необходимо применить <tex>n</tex> раз операцию добавления элемента к последней версии дерева. Для того, чтобы добавить новый элемент к <tex>k</tex>-ой версии дерева, необходимо проверить, является ли оно полным бинарным. Если да, то создадим новый корень, левым сыном сделаем <tex>roots[k]</tex>. Иначе, сделаем копию корня исходной версии. Добавим корень в конец массива корней. Далее, спускаясь от корня к первому свободному листу, будем создавать несуществующие узлы и клонировать существующие. После этого в новой ветке необходимо обновить значение функции и некоторые указатели дочерних элементов. Поэтому, возвращаясь из рекурсии, будем менять один указатель на только что созданную или скопированную вершину, а также обновим значение функции, для которой строилось дерево. После этой операции в дереве появится новая версия, содержащая вставленный элемент.
*[http://neerc.ifmo.ru/wiki/index[Несогласованные поддеревья.php?title=%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0_%D0%B2_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%B5_%D0%BE%D1%82%D1%80%D0%B5%D0%B7%D0%BA%D0%BE%D0%B2_%D1%81%D0%BD%D0%B8%D0%B7%D1%83 - Реализация запросов к дереву отрезков снизумассового обновления]]
==Источники информации== * [http://neerc.ifmohabrahabr.ru/wikipost/index.php?title=%D0%9D%D0%B5%D1%81%D0%BE%D0%B3%D0%BB%D0%B0%D1%81%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D1%8C%D1%8F._%D0%A0%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%BC%D0%B0%D1%81%D1%81%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%BD%D0%BE%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F - Реализация массового обновления115026/ Хабрахабр — Статья Максима Ахмедова]
* [http://e-maxx.ru/algo/segment_tree - MAXimal :: algo :: Дерево отрезков]
* [http://ru.wikipedia.org/wiki/%D0%94%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BE%D1%82%D1%80%D0%B5%D0%B7%D0%BA%D0%BE%D0%B2 - Википедия — Дерево отрезков — Википедия]
* [http://ru.wikipedia.org/wiki/Моноид - Википедия — Моноид — Википедия]
[[Категория: Дискретная математика и алгоритмы]]
[[Категория: Дерево отрезков]]
[[Категория: Структуры данных]]