<?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=46.232.216.122&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=46.232.216.122&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/46.232.216.122"/>
		<updated>2026-06-11T14:08:59Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=82233</id>
		<title>Centroid decomposition</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=82233"/>
				<updated>2022-03-19T14:13:09Z</updated>
		
		<summary type="html">&lt;p&gt;46.232.216.122: Исправлена ошибка в реализации&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Центроидная декомпозиция (англ. ''centroid decomposition'') {{---}} это структура данных, позволяющая отвечать на запросы на дереве. Чаще всего это запросы, связанные с нахождением функции на вершинах, связанных неравенством на расстояние между ними в дереве. Также иногда применяется для запросов на путях в дереве.&lt;br /&gt;
&lt;br /&gt;
== Введение ==&lt;br /&gt;
Рассмотрим &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt; задачи на обычном массиве (в дальнейшем мы будем их обобщать на случай дерева):&lt;br /&gt;
&lt;br /&gt;
Задача &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;:&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Есть массив &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; положительных целых чисел из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; элементов. Также дано число &amp;lt;tex&amp;gt;W \geqslant 0&amp;lt;/tex&amp;gt; и число &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt;. Требуется найти количество пар &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt; индексов массива, таких что &amp;lt;tex&amp;gt;|j - i| \leqslant l &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\sum\limits_{k=i}^{j} a_k \leqslant W&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
Задача &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;:&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Есть прямая дорога, на которой расположены &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; городов. В некоторых городах есть госпитали, которые могут принимать больных. Поступают запросы вида:&lt;br /&gt;
* дан город &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, в котором находится больной и требуется найти такой город &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, который может принимать больных и &amp;lt;tex&amp;gt;|u - v|&amp;lt;/tex&amp;gt; минимально возможное.&lt;br /&gt;
* дан город &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и сказано, что больше он не будет принимать больных&lt;br /&gt;
* дан город &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; и сказано, что теперь он может принимать больных&lt;br /&gt;
}}&lt;br /&gt;
Для начала решим обе задачи. &lt;br /&gt;
Первая задача решается методом [[Сортировка_слиянием|«разделяй и властвуй»]] {{---}} давайте разделим массив &amp;lt;tex&amp;gt;a[0 \dots n-1]&amp;lt;/tex&amp;gt; на 2 массива &amp;lt;tex&amp;gt;a[0\dots\dfrac{n}{2} - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[\dfrac{n}{2} \dots n-1]&amp;lt;/tex&amp;gt; и рекурсивно решим задачу для каждого из них. Осталось научиться находить количество искомых пар &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, таких что &amp;lt;tex&amp;gt;i &amp;lt; \dfrac{n}{2},\text{ }j \geqslant \dfrac{n}{2}&amp;lt;/tex&amp;gt;. Для этого воспользуемся другой известной техникой {{---}} методом двух указателей. Посчитаем массив префиксных сумм для правой половины &amp;lt;tex&amp;gt;pref[i] = \sum\limits_{j=\frac{n}{2}}^{i} a_j&amp;lt;/tex&amp;gt; и суффиксных &amp;lt;tex&amp;gt;(suf[i] = \sum\limits_{j=i}^{\frac{n}{2} + 1} a_j)&amp;lt;/tex&amp;gt; {{---}} для левой. Заведем два указателя &amp;lt;tex&amp;gt;(p_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_2)&amp;lt;/tex&amp;gt;. Изначально установим &amp;lt;tex&amp;gt;p_1 = \dfrac{n}{2} - l + 1,\text{ }p_2 = \dfrac{n}{2}&amp;lt;/tex&amp;gt;. Пока &amp;lt;tex&amp;gt;p_2 - 1&amp;gt; \dfrac{n}{2}&amp;lt;/tex&amp;gt; и&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;pref[p_2] + suf[p_1] &amp;gt; W &amp;lt;/tex&amp;gt; будем уменьшать &amp;lt;math&amp;gt;p_2&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;. Если после этого &amp;lt;math&amp;gt;pref[p_2] + suf[p_1] \leqslant W&amp;lt;/math&amp;gt;, то к ответу прибавим &amp;lt;math&amp;gt;(p_2 - \dfrac{n}{2} + 1) \cdot (\dfrac{n}{2} - p_1)&amp;lt;/math&amp;gt;, после чего увеличим &amp;lt;math&amp;gt;p_1&amp;lt;/math&amp;gt; на &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;. Так будем делать, пока &amp;lt;math&amp;gt;p_1 &amp;lt; \dfrac{n}{2}&amp;lt;/math&amp;gt;. В конце сложим текущий ответ и ответы для половин массива {{---}} получим ответ на задачу. Время работы такого алгоритма: &amp;lt;tex&amp;gt;T(n) = 2 \cdot T(n / 2) + O(n) = O(n*log(n))&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вторая задача имеет запросы на изменение и поэтому надо применить динамическую версию «разделяй и властвуй» {{---}} [[Дерево_отрезков._Построение|дерево отрезков]]. Построим дерево отрезков,&lt;br /&gt;
поддерживающее 2 вида запросов: присвоение в точке и минимум на отрезке. Изначально сделаем так, чтобы дереву отрезков соответствовал массив &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt;, такой что &amp;lt;tex&amp;gt;b_i = 0&amp;lt;/tex&amp;gt;, если в &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-м городе принимает госпиталь и &amp;lt;tex&amp;gt;b_i = 1&amp;lt;/tex&amp;gt; иначе. Когда в каком-то городе открывается/закрывается госпиталь {{---}} делаем запрос на изменение в дереве отрезков. Когда требуется узнать ближайший госпиталь к &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-му городу, можно воспользоваться одной из следующих идей: &lt;br /&gt;
* &amp;lt;tex&amp;gt;(O(n \cdot log^2(n))&amp;lt;/tex&amp;gt; Бинарным поиском ищем ближайший слева и ближайший справа к &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;-му городу госпиталь (такой город &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt;, что &amp;lt;tex&amp;gt;\min\limits_{k=i..j}b_k= 1)&amp;lt;/tex&amp;gt;. Для этого внутри бинарного поиска каждый раз делаем запрос на поиск минимума в дереве отрезков.  &lt;br /&gt;
* &amp;lt;tex&amp;gt;(O(n \cdot \log(n))&amp;lt;/tex&amp;gt; Будем одним спуском/подъемом по дереву определять, куда нам нужно идти (в левое или правое поддерево), тем самым делая одновременно и бинарный поиск, и спуск/подъем по дереву.&lt;br /&gt;
&lt;br /&gt;
== Статическая центроидная декомпозиция ==&lt;br /&gt;
Перейдем к обобщению поставленных задач на случай дерева.&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Есть взвешенное дерево &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; вершин, в каждой вершине которого написаны положительные целые числа. Также по-прежнему даны числа &amp;lt;tex&amp;gt;W \geqslant 0&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt;. Требуется найти количество пар &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt; вершин дерева, таких что расстояние между ними не превосходит &amp;lt;math&amp;gt;l&amp;lt;/math&amp;gt; по числу ребер и не превосходит &amp;lt;math&amp;gt;W&amp;lt;/math&amp;gt; по сумме весов&amp;lt;ref&amp;gt;[http://neerc.ifmo.ru/school/camp-2016/problems/20160324a1.pdf  Сайт с задачами Санкт-Петербургских сборов к РОИ 2016]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Для решения новой задачи применим ту же идею, что и была до этого {{---}} «разделяй и властвуй». Для этого нам потребуется следующий объект:&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|id=191213&lt;br /&gt;
|definition =&lt;br /&gt;
'''Центроидом дерева''' (англ. ''centroid'') называется такая вершина &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;, после удаления которой дерево разбивается на несколько &amp;lt;math&amp;gt;(k)&amp;lt;/math&amp;gt; поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,\dots, t_k&amp;lt;/tex&amp;gt;, таких что для каждого &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt;: &amp;lt;tex&amp;gt;|t_i| \leqslant \dfrac{n}{2}&amp;lt;/tex&amp;gt;, то есть размер каждого поддерева не превосходит половины размера исходного дерева.&lt;br /&gt;
}}&lt;br /&gt;
Итак, в случае дерева идея «разделяй и властвуй» из предыдущего пункта будет формулироваться так: [[#l1|найдем центроид]]. Предположим, что мы сумели найти центроид за &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; {{---}} размер дерева. Тогда, как и в упрощенной версии задачи {{---}} рекурсивно найдем ответ для всех поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,\dots, t_k&amp;lt;/tex&amp;gt;, после чего попытаемся найти недостающие пары вершин, находящиеся в разных поддеревьях и удовлетворяющих вопросу задачи. Для этого будем отвечать на следующие запросы: пусть мы сейчас считаем все пары, где первая из вершин находится в поддереве &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; и мы в некоторой структуре данных &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; храним все вершины остальных деревьев (каждую вершину задаем парой &amp;lt;math&amp;gt;(depth(v), length(v))&amp;lt;/math&amp;gt; {{---}} глубина вершины и длина пути до нее из корня поддерева), расстояние до которых от корня их поддерева не превышает &amp;lt;math&amp;gt;min(l, n)&amp;lt;/math&amp;gt;. Тогда просто пройдемся по всем вершинам &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; поддерева &amp;lt;math&amp;gt;t_i&amp;lt;/math&amp;gt; и прибавим к ответу число вершин в структуре &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt;, таких, что &amp;lt;tex&amp;gt;depth(u) \leqslant l - depth(v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;length(u) \leqslant l - length(v)&amp;lt;/tex&amp;gt;. Это двумерные запросы, на которые можно отвечать за &amp;lt;math&amp;gt;O(log^2(n)&amp;lt;/math&amp;gt; с помощью [[Многомерное_дерево_отрезков|2d-дерева отрезков]], либо за &amp;lt;math&amp;gt;O(\log(n))&amp;lt;/math&amp;gt; с помощью [[Перечисление_точек_в_произвольном_прямоугольнике_за_n_*_log_%5E(d_-_1)_n_(range_tree)|техники поиска точек в d-мерном пространстве]]. Также читателю предлагается придумать и более эффективные и простые способы решить эту подзадачу.&lt;br /&gt;
&lt;br /&gt;
Оценим итоговое время работы алгоритма: &amp;lt;tex&amp;gt;T(n) = k \cdot T(n / k) + O(n \cdot \log(n))&amp;lt;/tex&amp;gt;. Решая это рекуррентное соотношение, получим &amp;lt;math&amp;gt;O(n \cdot \log(n))&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Теперь докажем лемму о существовании центроида и опишем алгоритм его эффективного поиска.&lt;br /&gt;
&lt;br /&gt;
=== Лемма о существовании центроида и алгоритм его нахождения. ===&lt;br /&gt;
{{Лемма|id=l1&lt;br /&gt;
|statement=&lt;br /&gt;
В любом дереве &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; существует центроид.&lt;br /&gt;
|proof=&lt;br /&gt;
Рассмотрим корень дерева &amp;lt;math&amp;gt;(r)&amp;lt;/math&amp;gt;. Положим изначально &amp;lt;math&amp;gt;v = r&amp;lt;/math&amp;gt;. Изначально &amp;lt;math&amp;gt;|subtree(v)| = n&amp;lt;/math&amp;gt;. Среди всех детей &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; выберем вершину &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; с максимальным размером поддерева. Если &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; {{---}} не центроид, то положим &amp;lt;math&amp;gt;v = u&amp;lt;/math&amp;gt; и продолжим выбор нового &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt;, иначе {{---}} остановимся. Докажем, что мы в какой-то момент остановимся. Пусть в произвольный момент времени &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; {{---}} не центроид и размер её наддерева меньше &amp;lt;math&amp;gt;\dfrac{n}{2}&amp;lt;/math&amp;gt;, значит максимальное поддерево имеет размер больше чем &amp;lt;math&amp;gt;\dfrac{n}{2}&amp;lt;/math&amp;gt;, то есть &amp;lt;math&amp;gt;|subtree(u)| &amp;gt; \dfrac{n}{2}&amp;lt;/math&amp;gt;, а значит размер &amp;quot;наддерева&amp;quot; вершины &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; равен &amp;lt;tex&amp;gt;n - |subtree(u)| &amp;lt; \dfrac{n}{2}&amp;lt;/tex&amp;gt;. При этом теперь размер любого поддерева, на которое распадется дерево t при удалении вершины &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; не превосходит &amp;lt;math&amp;gt;|subtree(u)| - 1&amp;lt;/math&amp;gt;, так как наддерево имеет размер меньше, чем поддерево &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt;, а любое поддерево вершины &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; имеет хотя бы на &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; вершину меньше (сама вершина &amp;lt;math&amp;gt;u)&amp;lt;/math&amp;gt;. По индукции получаем, что в любой момент времени размер наддерева вершины &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; меньше &amp;lt;math&amp;gt;\dfrac{n}{2}&amp;lt;/math&amp;gt;, значит мы будем спускаться только вниз по дереву &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;, и при переходе к вершине &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; {{---}} сыну &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; размер максимального поддерева уменьшится как минимум на &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt;. Значит не более чем за &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; шагов наши действия прекратятся и мы окажемся в центроиде дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;.&lt;br /&gt;
Итак, мы конструктивно доказали существование центроида и привели линейный относительно размера дерева алгоритм его нахождения. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== Реализация ===&lt;br /&gt;
&lt;br /&gt;
Поиск центроида в дереве:&lt;br /&gt;
&lt;br /&gt;
  '''int''' &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;('''int[]''' children[n], '''int''' v, '''int[]''' sz, '''int''' tree_size)&lt;br /&gt;
     max_subtree = -1&lt;br /&gt;
     '''for''' u : children(v)&lt;br /&gt;
          '''if''' sz[u] &amp;gt; tree_size / 2 '''and''' sz[u] &amp;gt; sz[max_subtree] &amp;lt;font color=green&amp;gt;// считаем sz[-1] = 0 &amp;lt;/font &amp;gt;&lt;br /&gt;
               max_subtree = u&lt;br /&gt;
     '''if''' max_subtree == -1&lt;br /&gt;
          return v&lt;br /&gt;
     '''else''' &lt;br /&gt;
          '''return''' &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;(children, max_subtree, sz, tree_size)&lt;br /&gt;
&lt;br /&gt;
Шаблон решения произвольной задачи на статическую центроидную декомпозицию:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;tex&amp;gt;\mathtt{solve}&amp;lt;/tex&amp;gt;('''int[]''' children[n], '''int''' v, '''int[]''' sz)&lt;br /&gt;
     c = &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;(children, max_subtree, sz, sz[v]) &amp;lt;font color=green&amp;gt;// находим c {{---}} центроид поддерева вершины v &amp;lt;/font &amp;gt;&lt;br /&gt;
     ch = children[c]&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{deleteEdges}&amp;lt;/tex&amp;gt;(c, children) &amp;lt;font color=green&amp;gt;// удаляем все ребра между вершиной с и детьми, чтобы мы не смогли из детей попасть в с. &lt;br /&gt;
         Это полезно делать, если решение подзадачи для поддерева предполагает проход &amp;lt;math&amp;gt;dfs&amp;lt;/math&amp;gt; &amp;lt;/font &amp;gt;&lt;br /&gt;
     '''for''' c2 : ch[c]&lt;br /&gt;
          &amp;lt;tex&amp;gt;\mathtt{solve}&amp;lt;/tex&amp;gt;(children, c2, sz)&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{mergeSolution}&amp;lt;/tex&amp;gt;(children, c2) &amp;lt;font color=green&amp;gt;// решаем для текущего поддерева &amp;lt;/font &amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Динамическая центроидная декомпозиция (дерево центроидной декомпозиции) ==&lt;br /&gt;
Теперь вернемся ко второй задаче введения. Для ее решения мы пользовались динамичекой версией «разделяй и властвуй» {{---}} деревом отрезков. В предыдущем пункте мы определили статический аналог «разделяй и властвуй» для дерева. Теперь обобщим этот метод для динамических задач.&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Деревом центроидов''' (или центроидной декомпозицией, англ. ''centroid decomposition tree'') дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; называют дерево &amp;lt;math&amp;gt;T(t)&amp;lt;/math&amp;gt;, построенное на вершинах дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; следующим образом:&lt;br /&gt;
* Пусть вершина &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; {{---}} центроид дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;. Объявим его корнем нового дерева &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
* Пусть при удалении вершины &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; из дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; оно распалось на поддеревья &amp;lt;tex&amp;gt;t_1, t_2,\dots, t_k&amp;lt;/tex&amp;gt;, тогда детьми вершины c объявим &amp;lt;tex&amp;gt;T(t_1), T(t_2),\dots, T(t_k)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
=== Свойства центроидной декомпозиции ===&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
'''Свойства центроидной декомпозиции''':&lt;br /&gt;
# Глубина дерева центроидов не превосходит &amp;lt;tex&amp;gt;\\log(n)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
# Каждая вершина &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; является центроидом одного из поддеревьев дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;&lt;br /&gt;
# Каждая вершина дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; принадлежит &amp;lt;math&amp;gt;O(\log(n))&amp;lt;/math&amp;gt; поддеревьям дерева &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; (еще говорят, что вершина принадлежит &amp;lt;math&amp;gt;O(\log(n))&amp;lt;/math&amp;gt; центроидам дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;, или что эти центроиды содержат вершину)&lt;br /&gt;
# Для любых вершин &amp;lt;tex&amp;gt;u, v \in T (u \neq v)&amp;lt;/tex&amp;gt; верно ровно одно из следующих трех утверждений: &lt;br /&gt;
#*&amp;lt;tex&amp;gt;T(v) \subset T(u)&amp;lt;/tex&amp;gt;&lt;br /&gt;
#* &amp;lt;tex&amp;gt;T(u) \subset T(v)&amp;lt;/tex&amp;gt;&lt;br /&gt;
#* &amp;lt;tex&amp;gt;T(u) \cap T(v) = \emptyset &amp;lt;/tex&amp;gt;&lt;br /&gt;
# Простой путь между любой парой вершин &amp;lt;math&amp;gt;u, v&amp;lt;/math&amp;gt; в дереве &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; содержит центроид &amp;lt;tex&amp;gt;c \in T(t)&amp;lt;/tex&amp;gt;, такой что &amp;lt;tex&amp;gt;u, v \in T(c)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
# Действительно, так как размер поддерева &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt; каждой вершины &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; дереве &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; не превосходит &amp;lt;tex&amp;gt;\dfrac{|subtree(c)|}{2}&amp;lt;/tex&amp;gt;, то при спуске в каждую следующую вершину на пути к любому листу в дереве &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; размер поддерева вершины, в которой мы сейчас находимся, уменьшается как минимум на &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;. Значит длина всего пути до листа не превосходит &amp;lt;math&amp;gt;\log(n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Второе свойство очевидно из построения дерева &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, так как если вершина принадлежит дереву центроидов &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, то она является центроидом, а из построения &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; мы знаем, что каждая вершина исходного дерева принадлежит и дереву &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Третье свойство {{---}} прямое следствие первых двух, так как вершина принадлежит любому центроиду &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; т.и т.т., когда &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; {{---}} отец вершины &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; в дереве центроидов. Так как вершина &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; точно принадлежит дереву &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; (свойство &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt;), то она лежит на каком-то пути в дереве &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, причем все ее родители (центроиды) ее содержат. А по свойству &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; длина любого вертикального (и даже простого) пути есть &amp;lt;math&amp;gt;O(\log(n))&amp;lt;/math&amp;gt;.&lt;br /&gt;
# Четвертое свойство очевидно из того, что &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; {{---}} дерево. Так как &amp;lt;math&amp;gt;T(u)&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;T(v)&amp;lt;/math&amp;gt; {{---}} поддеревья различных вершин дерева &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, то либо они не пересекаются, либо &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; {{---}} предок &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, и значит &amp;lt;tex&amp;gt;T(v) \subset T(u)&amp;lt;/tex&amp;gt;, либо &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; {{---}} предок &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt;, и значит &amp;lt;tex&amp;gt;T(u) \subset T(v)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Для доказательства последнего свойства в качестве вершины &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; выберем &amp;lt;math&amp;gt;lca(u, v)&amp;lt;/math&amp;gt; в дереве центроидов &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;. Покажем, что так выбранная вершина &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; удовлетворяет заявленным свойствам. То, что &amp;lt;tex&amp;gt;u, v \in T(c)&amp;lt;/tex&amp;gt; {{---}} очевидно по определению &amp;lt;math&amp;gt;lca&amp;lt;/math&amp;gt;, так как каждый предок любой вершины в дереве центроидов содержит эту вершину. Теперь докажем, что &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; лежит на пути между парой вершин &amp;lt;math&amp;gt;u, v&amp;lt;/math&amp;gt;. Так как &amp;lt;math&amp;gt;c = lca(u, v)&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, то из &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; нет ребра в такого сына, который содержит одновременно &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; в своем поддереве (в дереве &amp;lt;math&amp;gt;T)&amp;lt;/math&amp;gt;, значит после удаления &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; дерево &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; разделится на несколько поддеревьев, таких что вершины &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; окажутся в разных компонентах связности. А значит найдется такое ребро &amp;lt;math&amp;gt;(c, x)&amp;lt;/math&amp;gt;, которое принадлежало пути из &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, но после удаления &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; удалилось. Это доказывает то, что вершина &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; лежала на пути из &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; в &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
С помощью описанных свойств дерева &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; мы можем решить задачу &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt; для дерева:&lt;br /&gt;
&lt;br /&gt;
=== Пример решения задачи с помощью центроидной декомпозиции === &lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Есть дерево &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt; из &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; вершин. В каждый момент времени любая вершина дерева может быть либо помечена, либо нет. Изначально помечена только вершина номер &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt;. Дан список из &amp;lt;math&amp;gt;m&amp;lt;/math&amp;gt; запросов: &lt;br /&gt;
* Вершину &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; пометили.&lt;br /&gt;
* С вершины &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; сняли пометку.&lt;br /&gt;
* Найти номер ближайшей к &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; помеченной вершины&amp;lt;ref&amp;gt;[http://neerc.ifmo.ru/school/camp-2016/problems/20160324a1.pdf  Сайт с задачами Санкт-Петербургских сборов к РОИ 2016]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Решение ====&lt;br /&gt;
&lt;br /&gt;
Построим центроидную декомпозицию &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; дерева &amp;lt;math&amp;gt;t&amp;lt;/math&amp;gt;. Изначально посчитаем для каждого центроида, содержащего вершину &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt; посчитаем расстояние до вершины &amp;lt;math&amp;gt;0&amp;lt;/math&amp;gt;. Для этого воспользуемся [[Метод_двоичного_подъема|методом двоичных подъемов для поиска lca пары вершин в дереве]], а также тем фактом, что если глубина &amp;lt;math&amp;gt;h(v)&amp;lt;/math&amp;gt; вершины &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; в дереве определена как расстояние от корня до вершины &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, то длина пути между парой вершин &amp;lt;math&amp;gt;(u, v)&amp;lt;/math&amp;gt; есть &amp;lt;tex&amp;gt;len(u, v) = h(u) + h(v) - 2 \cdot h(lca(u, v))&amp;lt;/tex&amp;gt;. Если изначально предпосчитать проходом [[Обход_в_глубину,_цвета_вершин| &amp;lt;math&amp;gt;dfs&amp;lt;/math&amp;gt;]] величины &amp;lt;math&amp;gt;h(v)&amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;, то ответ на запрос &amp;lt;math&amp;gt;len(u, v)&amp;lt;/math&amp;gt; можно делать за время &amp;lt;math&amp;gt;O(\log(n))&amp;lt;/math&amp;gt; с &amp;lt;tex&amp;gt;O(n \cdot \log(n)) &amp;lt;/tex&amp;gt;доп. памятью. Также можно воспользоваться техникой [[Сведение_задачи_LCA_к_задаче_RMQ|сведения задачи LCA к RMQ]] и решить с &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; дополнительной памятью и &amp;lt;math&amp;gt;O(1)&amp;lt;/math&amp;gt; времени на запрос. Теперь научимся отвечать на запросы. Из последнего свойства центроидной декомпозиции видно, что если &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; {{---}} искомая ближайшая помеченная вершина к &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt;, то путь между ними содержит центроид &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt;, такой что &amp;lt;tex&amp;gt;u, v \in T(c)&amp;lt;/tex&amp;gt;, причем &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; {{---}} предок одновременно вершин &amp;lt;math&amp;gt;u, v&amp;lt;/math&amp;gt; в дереве&amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;. Поэтому заведем [[Красно-черное_дерево|двоичное дерево поиска]] для каждого центроида &amp;lt;math&amp;gt;c \in T&amp;lt;/math&amp;gt;. В этой структуре для каждой вершины &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; будем хранить пары &amp;lt;math&amp;gt;(len(c, u), u)&amp;lt;/math&amp;gt; для всех помеченных вершин &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt; в поддереве центроидов &amp;lt;math&amp;gt;T(c)&amp;lt;/math&amp;gt;. Когда приходит запрос пометить вершину &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; {{---}} добавим в структуру данных для всех предков &amp;lt;math&amp;gt;p_c&amp;lt;/math&amp;gt; вершины &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; в дереве &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; пары &amp;lt;math&amp;gt;(len(p_c, v), v)&amp;lt;/math&amp;gt;. Мы совершим &amp;lt;math&amp;gt;O(\log(n))&amp;lt;/math&amp;gt; добавлений, затратив &amp;lt;math&amp;gt;O(\log(n))&amp;lt;/math&amp;gt; действий на каждое. Запрос снятия пометки с вершины обрабатывается аналогичными удалениями. Запрос поиска ближайшей к &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; помеченной вершины {{---}} это запрос поиска вершины &amp;lt;math&amp;gt;u&amp;lt;/math&amp;gt;, такой что  величина &amp;lt;math&amp;gt;len(c, u) + len(c, v)&amp;lt;/math&amp;gt; минимальна, где &amp;lt;math&amp;gt;c&amp;lt;/math&amp;gt; {{---}} предок &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; в дереве центроидов (по пятому свойству, нас интересуют именно такие &amp;lt;math&amp;gt;c)&amp;lt;/math&amp;gt;. Этот запрос занимает так же &amp;lt;tex&amp;gt;O(log^2(n))&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
Итак, мы научились решать задачу с &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; дополнительной памятью и временной сложностью &amp;lt;math&amp;gt;O(log^2(n))&amp;lt;/math&amp;gt; на запрос любого типа с предварительным предпосчетом за &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Варианты хранения центроидной декомпозиции ==&lt;br /&gt;
Для хранения дерева центроидов &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; есть &amp;lt;math&amp;gt;2&amp;lt;/math&amp;gt; подхода, имеющих свои преимущества и недостатки:&lt;br /&gt;
* Для каждой вершины &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; исходного дерева запомним величину &amp;lt;math&amp;gt;p_v&amp;lt;/math&amp;gt; {{---}} номер предка вершины &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; в дереве &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Этот подход наиболее экономный по памяти &amp;lt;math&amp;gt;(O(n))&amp;lt;/math&amp;gt;, но уступает в скорости и функциональности.&lt;br /&gt;
&lt;br /&gt;
* Для каждой вершины &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; исходного дерева будем хранить весь массив предков &amp;lt;math&amp;gt;p[v]&amp;lt;/math&amp;gt; в дереве центроидов.&lt;br /&gt;
&lt;br /&gt;
Этот подход уступает в количестве необходимой дополнительной памяти &amp;lt;tex&amp;gt;(O(n \cdot \log(n))&amp;lt;/tex&amp;gt; суммарно), но имеет ряд преимуществ:&lt;br /&gt;
&lt;br /&gt;
#При проходе по массиву предков фиксированной вершины будет выигрыш в скорости работы, так как весь массив будет лежать непрерывным блоком данных и следовательно будет закэширован&lt;br /&gt;
# На массиве предков можно строить различные структуры данных (такие как, например, дерево отрезков) для быстрого (в случае с деревом отрезков &amp;lt;math&amp;gt;O(log(\log(n)))&amp;lt;/math&amp;gt; на запрос) поиска предка с необходимыми свойствами. Так, например, в описанной выше задаче про помеченные вершины наибольшего общего предка можно искать методом двоичных подъемов за &amp;lt;math&amp;gt;O(\log(\log(n))&amp;lt;/math&amp;gt; на запрос, так как размер массива предков есть &amp;lt;math&amp;gt;O(\log(n))&amp;lt;/math&amp;gt; (по свойству &amp;lt;math&amp;gt;1&amp;lt;/math&amp;gt; центроидной декомпозиции). Используя эту оптимизацию можно получить время &amp;lt;math&amp;gt;O(\log(n)) + O(\log(\log(n)) = O(\log(n))&amp;lt;/math&amp;gt; на запрос нахождения ближайшей помеченной вершины. Чтобы добиться улучшенной асимптотики для запросов изменения можно хранить дерево отрезков на каждом из путей &amp;lt;math&amp;gt;p[v]&amp;lt;/math&amp;gt;, в каждой вершине которого хранить двоичное дерево поиска и поддерживать отложенные операции. Тогда ответ на эти запросы будет занимать &amp;lt;math&amp;gt;O(\log(n) \cdot \log(\log(n))&amp;lt;/math&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
&lt;br /&gt;
*[[:Дерево_отрезков._Построение|Дерево отрезков]]&lt;br /&gt;
*[[:Heavy-light_декомпозиция|Heavy-light декомпозиция]]&lt;br /&gt;
*[[:Метод_двоичного_подъема| Метод двоичного подъема]]&lt;br /&gt;
&lt;br /&gt;
== Примечания == &lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [https://threads-iiith.quora.com/Centroid-Decomposition-of-a-Tree  Quora {{---}} Centroid Decomposition of a Tree]&lt;br /&gt;
* [http://acm.math.spbu.ru/~sk1/mm/lections/zksh2016-centroid/conspect.pdf  ЗКШ {{---}} Конспект лекции про центроидную декомпозицию]&lt;br /&gt;
* [https://neerc.ifmo.ru/school/archive/2014-2015/ru-olymp-roi-2015-analysis.pdf  Разбор задач РОИ 2015]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;/div&gt;</summary>
		<author><name>46.232.216.122</name></author>	</entry>

	</feed>