Link-Cut Tree — различия между версиями
Lena (обсуждение | вклад) (→Оценка времени работы) |
Lena (обсуждение | вклад) (→Оценка времени работы) |
||
| Строка 100: | Строка 100: | ||
По лемме, количество легких dashed-ребер, преобразованных в solid, будет не больше, чем <tex>\log n</tex>. | По лемме, количество легких dashed-ребер, преобразованных в solid, будет не больше, чем <tex>\log n</tex>. | ||
| − | Обозначим за <tex>F</tex> лес деревьев, в которых каждое ребро либо solid, либо dashed, a <tex>F'</tex> - лес, получившийся из <tex>F</tex> после одного вызова <tex>expose</tex>. Определим потенциал <tex>\Phi _{a}(F) = n - 1 - |\{ | + | Обозначим за <tex>F</tex> лес деревьев, в которых каждое ребро либо solid, либо dashed, a <tex>F'</tex> - лес, получившийся из <tex>F</tex> после одного вызова <tex>expose</tex>. Определим потенциал <tex>\Phi _{a}(F) = n - 1 - |\{H \cap solid-edges\}|</tex>, <tex>\Delta \Phi _{a}</tex> - увеличение <tex>\Phi _{a}</tex> после одной операции <tex>expose</tex>. |
| − | + | {{Лемма | |
| + | |id = Lemma2 | ||
| + | |statement= <tex>V = M + \Delta \Phi _{a} \leqslant 1 + 2\log n </tex> | ||
| + | |||
| + | |proof= | ||
<tex>V = M + \Delta \Phi _{a}\\ | <tex>V = M + \Delta \Phi _{a}\\ | ||
= M + |H \cap S \rightarrow D| - |H \cap D \rightarrow S| \\ | = M + |H \cap S \rightarrow D| - |H \cap D \rightarrow S| \\ | ||
\leqslant M + |L \cap D \rightarrow S| - |H \cap D \rightarrow S| \\ | \leqslant M + |L \cap D \rightarrow S| - |H \cap D \rightarrow S| \\ | ||
| − | = 2 | + | = 2 \times |L \cap D \rightarrow S| \\ |
| − | =2 | + | =2 \times \log n |
</tex> | </tex> | ||
| − | + | }} | |
| Строка 117: | Строка 121: | ||
Докажем, что амортизационная стоимость операции <tex>expose</tex> равна <tex>O(log(n))</tex> | Докажем, что амортизационная стоимость операции <tex>expose</tex> равна <tex>O(log(n))</tex> | ||
| − | Пусть <tex>s(v)</tex> - количество вершин в поддеревьях <tex>v</tex> (здесь имеется в виду splay-дерево пути, котоый строится в ходе выполнения <tex>expose</tex>). | + | Пусть <tex>s(v)</tex> - количество вершин в поддеревьях <tex>v</tex> (здесь имеется в виду splay-дерево пути, котоый строится в ходе выполнения <tex>expose</tex>), <tex>r(v) = log(s(v))</tex>. По [[Splay-дерево#Lemma1|лемме]] стоимость ''i''-той операции <tex>splay</tex> не превосходит <tex>1 + 3 \times (r(t) - r(v))</tex>. Это приводит к тому, что амортизационная стоимость <tex>expose</tex> ограничена следующим значением: |
<tex>3 * \log n - 3*\log (s(v)) + M</tex> | <tex>3 * \log n - 3*\log (s(v)) + M</tex> | ||
Здесь <tex>M = O(\log n)</tex>, поэтому амортизационная стоимость <tex>expose</tex> равна <tex>O(\log n)</tex> | Здесь <tex>M = O(\log n)</tex>, поэтому амортизационная стоимость <tex>expose</tex> равна <tex>O(\log n)</tex> | ||
Версия 15:01, 10 июня 2014
Link-cut tree — это структура данных, которая хранит лес деревьев и позволяет выполнять следующие операции:
- искать минимум на пути от вершины до корня;
- прибавлять константу на пути от вершины до корня;
- link(u,w) -- подвешивать одно дерево на другое;
- cut(v) -- отрезать дерево с корнем в вершине v.
Содержание
Решение задачи в частном случае
Сначала научимся выполнять эти операции для частного случая, в котором все деревья - это пути. Для этого представим путь в виде splay-дерева, в котором ключи выбираются равными глубине вершины.Тогда операциям link и cut будут соответствовать merge и split.
Чтобы прибавлять заданное число на пути от вершины до корня, будем в каждой вершине хранить величину , которая равна разнице между весом вершины и весом её родителя. Для корня это значение равно весу самого корня. Поэтому вес вершины определятся следующим образом:
сумма
При прибавлении на пути от вершины до корня, сначала вызывается , после чего в левом поддереве находятся вершины, которые лежат на пути к корню. Затем надо прибавить к и, чтобы сохранить веса вершин, которые находятся ниже в пути, вычесть от .
Для поиска минимума поступим аналогично. Определим таким образом, чтобы сохранялся следующий инвариант: . Пусть и дети , тогда
Чтобы найти минимум на пути, надо вызвать , а затем сравнить минимум и минимум её левого ребенка.
Link-cut tree
Чтобы обобщить, разобьем дерево на множество непересекающихся путей. Каждое ребро обозначим либо solid-ребром, либо dashed-ребром. Все пути в представляемом дереве хранятся в виде splay-деревьев. Корень каждого splay-дерева хранит указатель на вершину-родителя.
expose(u)
Ключевая операция в link-cut-деревьях — . После её выполнения лежит на одном пути с корнем представляемого дерева и при этом становится корнем в splay-дереве получившегося пути.
expose(u)
splay(u)
v <- u
while (v != root)
p <- pathparent(v) //получаем указатель на ближайшую вершину пути, пересекающего путь от u до корня
splay(p) //теперь в правом поддереве p находятся вершины пути, которые находятся ниже чем p в link-cut-дереве,
parent(right(p)) <- null //поэтому правое поддерево p делаем новым путем
pathparent(right(p)) <- p
right(p) <- v //объединяем оставшийся и построенный пути
Δw(v) -= Δw(p)
Δmin(p) = min{0, Δmin(left(p)) + Δw(left(p)), Δmin(right(p)) + Δw(right(p))}
pathparent(v) <- null
v <- p
splay(u)
add(v, c)
Чтобы прибавить константу на пути от до корня link-cut-дерева вызовем , что построит запрашиваемый путь в виде splay-дерева, в котором - корень, и в левом поддереве находятся вершины, которые находятся выше чем в link-cut-дереве (то есть все вершины пути без ), а в правом - те, что ниже. Тогда прибавим к и вычтем константу от правого ребенка , чтобы скомпенсировать разницу и сохранить инвариант.
add(v, c)
expose(v)
Δw(v) += c
Δw(right(v)) -= c
min(v)
Построим splay-дерево для пути и сравним минимум корня c минимумом в левом поддереве:
min(v)
expose(v)
if (Δmin(left(v)) + Δw(left(v)) < Δw(v))
then
return Δmin(left(v)) + Δw(left(v))
else
return Δw(v)
link(v, u)
Если - корень, а - вершина в другом дереве, то соединяет два дерева добавлением ребра , причем становится родителем .
link(v, u)
expose(v) //теперь v - корень в splay-дереве пути и не имеет левого ребенка(так как ключ равен глубине в представляемом дереве)
expose(u)
Δw(u) -= Δw(v) //чтобы сделать u родителем v в представляемом дереве 1. делаем путь, содержащий u, левым ребенком v в splay-дереве
parent(u) = v // 2. обновляем Δw, Δmin
left(v) = u
Δmin(v) = min{0, Δmin(u) + Δw(u), Δmin(right(v)) + Δw((right(v)))}
cut(v)
Отрезает дерево с корнем . После вызова станет корнем splay-дерева, и в правом поддереве будут содержатся все вершины, которые были ниже в представляемом дереве, а в левом - те что выше. Обнулив указатель на левого ребенка и на родителя в левом поддереве, получим требуемое.
cut(v)
expose(v)
Δw(left(v)) += Δw(v)
Δmin(v) = min{0, Δmin(right(v)) + Δw(right(v))}
left(v) = null
parent(left(v)) = null
Оценка времени работы
Назовем ребро из в её родителя тяжелым, если количество детей .
| Лемма: |
На пути от вершины до корня не больше легких ребер. |
Операция осуществляется с помощью последовательности преобразований dashed-ребра в solid-ребро и другого solid-ребра в dashed-ребро. Обозначим количество таких преобразований за . Найдем количество преобразований сделанных в течение . Пусть - множество всех тяжелых ребер, - все легкие ребра, - множество solid-ребер, преобразованных в dashed в течение одного , - множество dashed-ребер, преобразованных в solid.
По лемме, количество легких dashed-ребер, преобразованных в solid, будет не больше, чем .
Обозначим за лес деревьев, в которых каждое ребро либо solid, либо dashed, a - лес, получившийся из после одного вызова . Определим потенциал , - увеличение после одной операции .
| Лемма: |
| Доказательство: |
Теперь проанализируем . Используя тот факт, что начальное значение не превосходит , приходим к тому, что для деревьев с вершинами, по крайней мере за операцию , среднее на одну операцию будет не больше, чем
Докажем, что амортизационная стоимость операции равна
Пусть - количество вершин в поддеревьях (здесь имеется в виду splay-дерево пути, котоый строится в ходе выполнения ), . По лемме стоимость i-той операции не превосходит . Это приводит к тому, что амортизационная стоимость ограничена следующим значением:
Здесь , поэтому амортизационная стоимость равна