<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=94.25.229.149&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=94.25.229.149&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/94.25.229.149"/>
		<updated>2026-04-14T19:03:42Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Level_Ancestor_problem&amp;diff=82649</id>
		<title>Level Ancestor problem</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Level_Ancestor_problem&amp;diff=82649"/>
				<updated>2022-07-28T10:58:18Z</updated>
		
		<summary type="html">&lt;p&gt;94.25.229.149: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Задача о уровне предка''' — (англ. &amp;quot;Level Ancestor problem&amp;quot;) является задачей о превращении данного подвешенного дерева &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; в структуру данных, которая сможет определить предка любого узла на заданном расстоянии от этого узла.&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дано подвешенное дерево &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; c &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; вершинами. Поступают запросы вида &amp;lt;tex&amp;gt;LA(v, k)&amp;lt;/tex&amp;gt;, для каждого из которых необходимо&lt;br /&gt;
найти предка вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, который находится на расстоянии &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; от корня дерева &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
== Использование Heavy-light декомпозиции ==&lt;br /&gt;
[[Файл:LevelAncestor.png|200px|thumb|right]]&lt;br /&gt;
Этот алгоритм базируется на различных способах [[Heavy-light декомпозиция | декомпозиции дерева]] (выберем heavy-light декомпозицию), из свойств этого разбиения следует,&lt;br /&gt;
что подняться на любую высоту из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; мы можем за время &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Данное разбиение можно строить за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;, что дает нам алгоритм за &amp;lt;tex&amp;gt;\langle O(n), O(\log n) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В данном примере поступает запрос LA(v, 2), на который алгоритм должен дать ответ h.&lt;br /&gt;
&lt;br /&gt;
== Алгоритм лестниц ==&lt;br /&gt;
=== Longest path decomposition &amp;lt;ref&amp;gt;[https://www.mi.fu-berlin.de/en/inf/groups/abi/teaching/lectures/lectures_past/WS0910/V____Discrete_Mathematics_for_Bioinformatics__P1/material/scripts/treedecomposition1.pdf Longest path decomposition]&amp;lt;/ref&amp;gt;===&lt;br /&gt;
Это декомпозиция дерева, которая разбивает его на множество вершинно-непересекающихся путей, идущих из каждой вершины в ее ребенка с самым глубоким поддеревом.&lt;br /&gt;
Сделаем ее следующим образом: обойдем дерево с помощью обхода в глубину, пусть мы стоим в вершине&lt;br /&gt;
&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, обойдем всех ее детей, добавив &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в путь, идущий в самое глубокое поддерево,&lt;br /&gt;
т.е. в котором находится вершина с самой большой глубиной.&lt;br /&gt;
Для каждой вершины сохраним номер пути в который она входит.&lt;br /&gt;
&lt;br /&gt;
=== Ladder decomposition ===&lt;br /&gt;
Это улучшение Longest-path декомпозиции, позволяющее, как мы потом докажем, подниматься на любую высоту за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;. Выполним его следующим образом: увеличим каждый путь в два раза вверх, для каждого нового пути сохраним все входящие в него вершины,&lt;br /&gt;
а для каждой вершины сохраним ее номер в пути, в который она входит. Построение обычной longest-path декомпозиции займет у&lt;br /&gt;
нас &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени (обход в глубину), удлинение каждого пути не ухудшит асимптотику.&lt;br /&gt;
&lt;br /&gt;
После этого посчитаем двоичные подъемы для каждой вершины за &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;, получим итоговую оценку &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt; на предподсчет.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Пусть после этого нам пришел запрос LA(v, k).&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;p[i] [v]&amp;lt;/tex&amp;gt; — &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-тый двоичный подъем в предка вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;&lt;br /&gt;
*&amp;lt;tex&amp;gt;way[v]&amp;lt;/tex&amp;gt; — путь, проходящий через данную вершину&lt;br /&gt;
*&amp;lt;tex&amp;gt;num[v]&amp;lt;/tex&amp;gt; — номер данной вершины на пути&lt;br /&gt;
*&amp;lt;tex&amp;gt;ladder[p][i]&amp;lt;/tex&amp;gt; — возвращает &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-тую вершину на пути &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   '''function''' LA('''int''' v,'''int''' k):&lt;br /&gt;
      '''int''' n = h(v) ''&amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// получаем глубину вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;&amp;lt;/font&amp;gt;''&lt;br /&gt;
      n = n - k;  ''&amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// на столько необходимо подняться до ответа&amp;lt;/font&amp;gt;''&lt;br /&gt;
      i = &amp;lt;tex&amp;gt;\lfloor \log_2 n \rfloor&amp;lt;/tex&amp;gt;&lt;br /&gt;
      v = p[i][v]  ''&amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// делаем максимально большой прыжок вверх&amp;lt;/font&amp;gt;''&lt;br /&gt;
      i = n - &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt;  ''&amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// на столько осталось еще подняться&amp;lt;/font&amp;gt;''&lt;br /&gt;
      '''return''' ladder[way[v]][num[v] - i] ''&amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// так как теперь &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и ответ находятся на одном пути&amp;lt;/font&amp;gt;''&lt;br /&gt;
&lt;br /&gt;
=== Доказательство корректности ===&lt;br /&gt;
Рассмотрим путь, на котором лежит вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; до удвоения. Он длины хотя бы &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt;, так как мы точно знаем, что существует вершина потомок &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, расстояние до которого ровно &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; (это вершина, из которой мы только что пришли). Значит, после удвоения этот путь стал длины хотя бы &amp;lt;tex&amp;gt;2^{i + 1}&amp;lt;/tex&amp;gt;, причем хотя бы &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; вершин в нем  — предки &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;. Это означает, что вершина, которую мы ищем, находится на этом пути (иначе бы мы могли до этого прыгнуть еще на &amp;lt;tex&amp;gt;2^i&amp;lt;/tex&amp;gt; вверх). Так как мы знаем позицию &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в этом пути, то нужную вершину мы можем найти за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Таким образом, наш алгоритм работает за &amp;lt;tex&amp;gt;\langle O(n\log n), O(1)\rangle &amp;lt;/tex&amp;gt; времени и за &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt; памяти. Методом четырех русских данный метод можно улучшить до &amp;lt;tex&amp;gt;\langle O(n), O(1)\rangle &amp;lt;/tex&amp;gt; с помощью оптимизации предподсчета.&lt;br /&gt;
&lt;br /&gt;
==  The Macro-Micro-Tree Algorithm ==&lt;br /&gt;
В данном разделе мы докажем, что предподсчет предыдущего алгоритма можно улучшить до &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Для начала рассмотрим алгоритм &amp;lt;tex&amp;gt;\langle O(L\log n + n), O(1)\rangle &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; это количество листьев.&lt;br /&gt;
*С помощью обхода в глубину запомним по одному листу в поддереве для каждой вершины&lt;br /&gt;
*Воспользуемся алгоритмом лестниц, но будем выполнять предподсчет только для листьев.&lt;br /&gt;
Рассмотрим как можно улучшить данный алгоритм:&lt;br /&gt;
*Зададим некую функцию &amp;lt;tex&amp;gt;S(n) = \dfrac{1}{4} \log_2 n&amp;lt;/tex&amp;gt;&lt;br /&gt;
*Посчитаем размер поддерева для каждой вершины с помощью обхода в глубину, после чего удалим все вершины размер поддерева которых меньше чем  &amp;lt;tex&amp;gt;S(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*Забудем на время про удаленные поддеревья, для оставшегося дерева наш алгоритм работает за  &amp;lt;tex&amp;gt;\langle O(\dfrac{n}{S(n)} \log n + n), O(1)\rangle &amp;lt;/tex&amp;gt;. Получаем алгоритм &amp;lt;tex&amp;gt;\langle O(n), O(1) \rangle &amp;lt;/tex&amp;gt;. Для удаленных поддеревьев же выполним полный предподсчет: таких деревьев не более чем &amp;lt;tex&amp;gt;2^{2S(n)}&amp;lt;/tex&amp;gt;, что дает асимптотику предподсчета &amp;lt;tex&amp;gt;O(\sqrt{n} \log^2{n}) = o(n) = O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В итоге полученный алгоритм действительно работает за &amp;lt;tex&amp;gt;\langle O(n), O(1)\rangle &amp;lt;/tex&amp;gt; времени и за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
== Сравнение с другими реализациями ==&lt;br /&gt;
Используя DFS посчитаем глубину каждой вершины дерева (это можно сделать за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;), после чего можем из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; подняться до необходимой глубины вершины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;,&lt;br /&gt;
что так же в худшем случае работает за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Получили алгоритм за &amp;lt;tex&amp;gt;\langle O(n), O(n) \rangle&amp;lt;/tex&amp;gt; времени и &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти, где время ответа на&lt;br /&gt;
запрос можно улучшить до &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; c помощью [[Метод двоичного подъёма | предподсчета двоичных подъемов]]  ,&lt;br /&gt;
но тогда и время предподсчета в наивной реализации (посчитать подъемы для всех вершин) ухудшится до &amp;lt;tex&amp;gt;\langle O(n \log n),&lt;br /&gt;
O(\log n)\rangle &amp;lt;/tex&amp;gt; времени и &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt; памяти. Также альтернативой данным двум алгоритмам является полный предподсчет всех возможных запросов, что соответственно дает нам асимптотику &amp;lt;tex&amp;gt;\langle O(n^2), O(1)\rangle &amp;lt;/tex&amp;gt;времени и &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
Сравнение различных асимптотик из данной статьи:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;clear:right;&amp;quot; cellpadding=&amp;quot;10&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
!&lt;br /&gt;
| Предподсчет&lt;br /&gt;
| Ответ на запрос&lt;br /&gt;
| Память&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
!Обычный подъем до нужного уровня&lt;br /&gt;
|&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
!Полный предподсчет&lt;br /&gt;
|&amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
!Двоичные подъемы&lt;br /&gt;
|&amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
!Декомпозиция&lt;br /&gt;
|&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
!Алгоритм лестниц&lt;br /&gt;
|&amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
!Macro-Micro-Tree Algorithm&lt;br /&gt;
|&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;||&amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
== См. также == &lt;br /&gt;
*[[Метод двоичного подъёма]]&lt;br /&gt;
*[[Heavy-light декомпозиция]]&lt;br /&gt;
== Примечания ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[https://www.cadmo.ethz.ch/education/lectures/HS18/SAADS/reports/5.pdf Level Ancestor problem simplified Cai Qi]&lt;br /&gt;
*[https://en.wikipedia.org/wiki/Level_ancestor_problem Wikipedia: LA]&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;/div&gt;</summary>
		<author><name>94.25.229.149</name></author>	</entry>

	</feed>