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

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=61580</id>
		<title>Centroid decomposition</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=61580"/>
				<updated>2017-06-14T10:53:47Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.157.37: /* Динамическая центроидная декомпозиция (дерево центроидной декомпозиции) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Centroid decomposition (рус. центроидная декомпозиция) - это структура данных, позволяющая отвечать на запросы на дереве. Чаще всего это запросы, связанные с нахождением функции на вершинах, связанных неравенством на расстояние между ними в дереве. Также иногда применяется для запросов на путях в дереве.&lt;br /&gt;
&lt;br /&gt;
== Введение ==&lt;br /&gt;
Рассмотрим 2 задачи на обычном массиве (в дальнейшем мы будем их обобщать на случай дерева):&lt;br /&gt;
&lt;br /&gt;
Задача 1&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_{i=0}^{n - 1} a_i \leqslant W&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
Задача 2:&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;
Первая задача решается методом [[Сортировка_слиянием|qevide&amp;amp;conqure (рус. разделяй и властвуй)]] - давайте разделим массив &amp;lt;tex&amp;gt;a[0...n-1]&amp;lt;/tex&amp;gt; на 2 массива &amp;lt;tex&amp;gt;a[0...\frac{n}{2} - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[\frac{n}{2}...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; \frac{n}{2}, j \geqslant \frac{n}{2}&amp;lt;/tex&amp;gt;. Для этого воспользуемся другой известной техникой - методом двух указателей. Посчитаем массив префиксных сумм для правой половины &amp;lt;tex&amp;gt;pref[i] = \sum_{j=\frac{n}{2}}^{i} a_j&amp;lt;/tex&amp;gt; и суффиксных (&amp;lt;tex&amp;gt;suf[i] = \sum_{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 = \frac{n}{2} - l + 1, p_2 = \frac{n}{2}&amp;lt;/tex&amp;gt;. Пока &amp;lt;tex&amp;gt;p_2 - 1&amp;gt; \frac{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 - \frac{n}{2} + 1) * (\frac{n}{2} - p_1)&amp;lt;/math&amp;gt;, посго, увеличим &amp;lt;math&amp;gt;p_1&amp;lt;/math&amp;gt; на &amp;lt;math/math&amp;gt;. Так будем делать, пока &amp;lt;math&amp;gt;p_1 &amp;lt; \frac{n}{2}&amp;lt;/math&amp;gt;. В конце сложим текущий ответ и ответы для половин массива - получим ответ на задачу. Асимптотика такого алгоритма : &amp;lt;tex&amp;gt;T(n) = 2 * T(n / 2) + O(n) = O(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вторая задача имеет запросы на изменение и поэтому надо применить динамическую версию qevide&amp;amp;conqure - [[Дерево_отрезков._Построение|дерево отрезков]]. Построим дерево отрезков,&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;, если в i-м городе принимает госпиталь и &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;) Бинарным поиском ищем ближайший слева и ближайший справа к i-му городу госпиталь (такой город &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 &amp;gt;= 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; по сумме весов.&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,..., 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 \frac{n}{2}&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;n&amp;lt;/math&amp;gt; - размер дерева. Тогда, как и в упрощенной версии задачи - рекурсивно найдем ответ для всех поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,..., 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 * 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;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
В любом дереве t существует центроид.&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; и продолжим выбор нового u, иначе - остановимся. Докажем, что мы в какой-то момент остановимся. Пусть в призвольный момент времени &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; - не центроид и размер её наддерева меньше &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;, значит максимальное поддерево имеет размер больше чем &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;|subtree(u)| &amp;gt; \frac{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; \frac{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;). По индукции получаем, что в любой момент времени размер наддерева вершины v меньше &amp;lt;math&amp;gt;\frac{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;
  '''int''' &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;('''int[]''' children[n], '''int''' v, '''int''' sz[n])&lt;br /&gt;
     max_subtree = -1&lt;br /&gt;
     '''for''' u : children(v)&lt;br /&gt;
          '''if''' sz[u] &amp;gt; sz[v] / 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)&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[n])&lt;br /&gt;
     c = &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;(children, max_subtree, sz) &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;// удаляем все ребра между вершиной с и детьми, чтобы мы не смогли из детей попасть в с. Это полезно делать, если решение  подзадачи для поддерева предполагает проход dfs &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;
Теперь вернемся ко второй задаче введения. Для ее решения мы пользовались динамичекой версией devide&amp;amp;conqure - деревом отрезков. В предыдущем пункте мы определили статический оналог devide&amp;amp;conqure для дерева. Теперь обобщим этот метод для динамических задач.&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&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; следующим образом :&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,..., t_k&amp;lt;/tex&amp;gt;, а центроиды этих поддеревьев - вершины &amp;lt;tex&amp;gt;c_1, c_2, ..., c_k&amp;lt;/tex&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;c_1, c_2,..., c_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Рекурсивно перейдем к построению для поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,..., 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;
|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;\frac{|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; т.и т.т., когда c - отец вершины &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; (свойство 2), то она лежит на каком-то пути в дереве &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, причем все ее родители (центроиды) ее содержат. А по свойству 1 длина любого вертикального (и даже простого) пути есть &amp;lt;math&amp;gt;O(log(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; мы можем решить задачу 2 для дерева :&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Есть страна, &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; городов которой связаны двустронними дорогами, причем так, чтобы получился минимальный связный граф на &amp;lt;math&amp;gt;n-1&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; хочет узнать номер ближайшего города, госпиталь которого открыт.&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;,&lt;br /&gt;
&lt;br /&gt;
// TODO :: дописать решение (мой код : https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220Bw29IKNdcznCYnVFbVo2alZiSzA%22]})&lt;br /&gt;
&lt;br /&gt;
== Варианты реализации ==&lt;br /&gt;
// TODO :: написать про то, что можно хранить предков (+память О(n), - скорость, - ничего нельзя сделать), а можно для каждой вершины - массив содержащих ее центроидов (+скорость(кэш), +масштабируемость(структуры данных на путях), - память n*logn)&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;/div&gt;</summary>
		<author><name>217.66.157.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=61579</id>
		<title>Centroid decomposition</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=61579"/>
				<updated>2017-06-14T10:52:20Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.157.37: /* Динамическая центроидная декомпозиция (дерево центроидной декомпозиции) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Centroid decomposition (рус. центроидная декомпозиция) - это структура данных, позволяющая отвечать на запросы на дереве. Чаще всего это запросы, связанные с нахождением функции на вершинах, связанных неравенством на расстояние между ними в дереве. Также иногда применяется для запросов на путях в дереве.&lt;br /&gt;
&lt;br /&gt;
== Введение ==&lt;br /&gt;
Рассмотрим 2 задачи на обычном массиве (в дальнейшем мы будем их обобщать на случай дерева):&lt;br /&gt;
&lt;br /&gt;
Задача 1&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_{i=0}^{n - 1} a_i \leqslant W&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
Задача 2:&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;
Первая задача решается методом [[Сортировка_слиянием|qevide&amp;amp;conqure (рус. разделяй и властвуй)]] - давайте разделим массив &amp;lt;tex&amp;gt;a[0...n-1]&amp;lt;/tex&amp;gt; на 2 массива &amp;lt;tex&amp;gt;a[0...\frac{n}{2} - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[\frac{n}{2}...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; \frac{n}{2}, j \geqslant \frac{n}{2}&amp;lt;/tex&amp;gt;. Для этого воспользуемся другой известной техникой - методом двух указателей. Посчитаем массив префиксных сумм для правой половины &amp;lt;tex&amp;gt;pref[i] = \sum_{j=\frac{n}{2}}^{i} a_j&amp;lt;/tex&amp;gt; и суффиксных (&amp;lt;tex&amp;gt;suf[i] = \sum_{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 = \frac{n}{2} - l + 1, p_2 = \frac{n}{2}&amp;lt;/tex&amp;gt;. Пока &amp;lt;tex&amp;gt;p_2 - 1&amp;gt; \frac{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 - \frac{n}{2} + 1) * (\frac{n}{2} - p_1)&amp;lt;/math&amp;gt;, посго, увеличим &amp;lt;math&amp;gt;p_1&amp;lt;/math&amp;gt; на &amp;lt;math/math&amp;gt;. Так будем делать, пока &amp;lt;math&amp;gt;p_1 &amp;lt; \frac{n}{2}&amp;lt;/math&amp;gt;. В конце сложим текущий ответ и ответы для половин массива - получим ответ на задачу. Асимптотика такого алгоритма : &amp;lt;tex&amp;gt;T(n) = 2 * T(n / 2) + O(n) = O(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вторая задача имеет запросы на изменение и поэтому надо применить динамическую версию qevide&amp;amp;conqure - [[Дерево_отрезков._Построение|дерево отрезков]]. Построим дерево отрезков,&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;, если в i-м городе принимает госпиталь и &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;) Бинарным поиском ищем ближайший слева и ближайший справа к i-му городу госпиталь (такой город &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 &amp;gt;= 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; по сумме весов.&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,..., 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 \frac{n}{2}&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;n&amp;lt;/math&amp;gt; - размер дерева. Тогда, как и в упрощенной версии задачи - рекурсивно найдем ответ для всех поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,..., 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 * 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;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
В любом дереве t существует центроид.&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; и продолжим выбор нового u, иначе - остановимся. Докажем, что мы в какой-то момент остановимся. Пусть в призвольный момент времени &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; - не центроид и размер её наддерева меньше &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;, значит максимальное поддерево имеет размер больше чем &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;|subtree(u)| &amp;gt; \frac{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; \frac{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;). По индукции получаем, что в любой момент времени размер наддерева вершины v меньше &amp;lt;math&amp;gt;\frac{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;
  '''int''' &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;('''int[]''' children[n], '''int''' v, '''int''' sz[n])&lt;br /&gt;
     max_subtree = -1&lt;br /&gt;
     '''for''' u : children(v)&lt;br /&gt;
          '''if''' sz[u] &amp;gt; sz[v] / 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)&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[n])&lt;br /&gt;
     c = &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;(children, max_subtree, sz) &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;// удаляем все ребра между вершиной с и детьми, чтобы мы не смогли из детей попасть в с. Это полезно делать, если решение  подзадачи для поддерева предполагает проход dfs &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;
Теперь вернемся ко второй задаче введения. Для ее решения мы пользовались динамичекой версией devide&amp;amp;conqure - деревом отрезков. В предыдущем пункте мы определили статический оналог devide&amp;amp;conqure для дерева. Теперь обобщим этот метод для динамических задач.&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&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; следующим образом :&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,..., t_k&amp;lt;/tex&amp;gt;, а центроиды этих поддеревьев - вершины &amp;lt;tex&amp;gt;c_1, c_2, ..., c_k&amp;lt;/tex&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;c_1, c_2,..., c_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Рекурсивно перейдем к построению для поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,..., 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;
|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;\frac{|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; т.и т.т., когда c - отец вершины &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; (свойство 2), то она лежит на каком-то пути в дереве &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, причем все ее родители (центроиды) ее содержат. А по свойству 1 длина любого вертикального (и даже простого) пути есть &amp;lt;math&amp;gt;O(log(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; мы можем решить задачу 2 для дерева :&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Есть страна, &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; городов которой связаны двустронними дорогами, причем так, чтобы получился минимальный связный граф на &amp;lt;math&amp;gt;n-1&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; хочет узнать номер ближайшего города, госпиталь которого открыт.&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;,&lt;br /&gt;
&lt;br /&gt;
// TODO :: дописать решение (мой код : https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220Bw29IKNdcznCYnVFbVo2alZiSzA%22]})&lt;br /&gt;
&lt;br /&gt;
== Варианты реализации ==&lt;br /&gt;
// TODO :: написать про то, что можно хранить предков (+память О(n), - скорость, - ничего нельзя сделать), а можно для каждой вершины - массив содержащих ее центроидов (+скорость(кэш), +масштабируемость(структуры данных на путях), - память n*logn)&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;/div&gt;</summary>
		<author><name>217.66.157.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=61578</id>
		<title>Centroid decomposition</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=61578"/>
				<updated>2017-06-14T10:50:10Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.157.37: /* Динамическая центроидная декомпозиция (дерево центроидной декомпозиции) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Centroid decomposition (рус. центроидная декомпозиция) - это структура данных, позволяющая отвечать на запросы на дереве. Чаще всего это запросы, связанные с нахождением функции на вершинах, связанных неравенством на расстояние между ними в дереве. Также иногда применяется для запросов на путях в дереве.&lt;br /&gt;
&lt;br /&gt;
== Введение ==&lt;br /&gt;
Рассмотрим 2 задачи на обычном массиве (в дальнейшем мы будем их обобщать на случай дерева):&lt;br /&gt;
&lt;br /&gt;
Задача 1&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_{i=0}^{n - 1} a_i \leqslant W&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
Задача 2:&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;
Первая задача решается методом [[Сортировка_слиянием|qevide&amp;amp;conqure (рус. разделяй и властвуй)]] - давайте разделим массив &amp;lt;tex&amp;gt;a[0...n-1]&amp;lt;/tex&amp;gt; на 2 массива &amp;lt;tex&amp;gt;a[0...\frac{n}{2} - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[\frac{n}{2}...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; \frac{n}{2}, j \geqslant \frac{n}{2}&amp;lt;/tex&amp;gt;. Для этого воспользуемся другой известной техникой - методом двух указателей. Посчитаем массив префиксных сумм для правой половины &amp;lt;tex&amp;gt;pref[i] = \sum_{j=\frac{n}{2}}^{i} a_j&amp;lt;/tex&amp;gt; и суффиксных (&amp;lt;tex&amp;gt;suf[i] = \sum_{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 = \frac{n}{2} - l + 1, p_2 = \frac{n}{2}&amp;lt;/tex&amp;gt;. Пока &amp;lt;tex&amp;gt;p_2 - 1&amp;gt; \frac{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 - \frac{n}{2} + 1) * (\frac{n}{2} - p_1)&amp;lt;/math&amp;gt;, посго, увеличим &amp;lt;math&amp;gt;p_1&amp;lt;/math&amp;gt; на &amp;lt;math/math&amp;gt;. Так будем делать, пока &amp;lt;math&amp;gt;p_1 &amp;lt; \frac{n}{2}&amp;lt;/math&amp;gt;. В конце сложим текущий ответ и ответы для половин массива - получим ответ на задачу. Асимптотика такого алгоритма : &amp;lt;tex&amp;gt;T(n) = 2 * T(n / 2) + O(n) = O(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вторая задача имеет запросы на изменение и поэтому надо применить динамическую версию qevide&amp;amp;conqure - [[Дерево_отрезков._Построение|дерево отрезков]]. Построим дерево отрезков,&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;, если в i-м городе принимает госпиталь и &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;) Бинарным поиском ищем ближайший слева и ближайший справа к i-му городу госпиталь (такой город &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 &amp;gt;= 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; по сумме весов.&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,..., 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 \frac{n}{2}&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;n&amp;lt;/math&amp;gt; - размер дерева. Тогда, как и в упрощенной версии задачи - рекурсивно найдем ответ для всех поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,..., 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 * 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;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
В любом дереве t существует центроид.&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; и продолжим выбор нового u, иначе - остановимся. Докажем, что мы в какой-то момент остановимся. Пусть в призвольный момент времени &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; - не центроид и размер её наддерева меньше &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;, значит максимальное поддерево имеет размер больше чем &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;|subtree(u)| &amp;gt; \frac{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; \frac{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;). По индукции получаем, что в любой момент времени размер наддерева вершины v меньше &amp;lt;math&amp;gt;\frac{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;
  '''int''' &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;('''int[]''' children[n], '''int''' v, '''int''' sz[n])&lt;br /&gt;
     max_subtree = -1&lt;br /&gt;
     '''for''' u : children(v)&lt;br /&gt;
          '''if''' sz[u] &amp;gt; sz[v] / 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)&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[n])&lt;br /&gt;
     c = &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;(children, max_subtree, sz) &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;// удаляем все ребра между вершиной с и детьми, чтобы мы не смогли из детей попасть в с. Это полезно делать, если решение  подзадачи для поддерева предполагает проход dfs &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;
Теперь вернемся ко второй задаче введения. Для ее решения мы пользовались динамичекой версией devide&amp;amp;conqure - деревом отрезков. В предыдущем пункте мы определили статический оналог devide&amp;amp;conqure для дерева. Теперь обобщим этот метод для динамических задач.&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
&amp;quot;&amp;quot;Деревом центроидов (или центроидной декомпозицией)&amp;quot;&amp;quot; дерева &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;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,..., t_k&amp;lt;/tex&amp;gt;, а центроиды этих поддеревьев - вершины &amp;lt;tex&amp;gt;c_1, c_2, ..., c_k&amp;lt;/tex&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;c_1, c_2,..., c_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Рекурсивно перейдем к построению для поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,..., 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;
|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;\frac{|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; т.и т.т., когда c - отец вершины &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; (свойство 2), то она лежит на каком-то пути в дереве &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, причем все ее родители (центроиды) ее содержат. А по свойству 1 длина любого вертикального (и даже простого) пути есть &amp;lt;math&amp;gt;O(log(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; мы можем решить задачу 2 для дерева :&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Есть страна, &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; городов которой связаны двустронними дорогами, причем так, чтобы получился минимальный связный граф на &amp;lt;math&amp;gt;n-1&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; хочет узнать номер ближайшего города, госпиталь которого открыт.&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;,&lt;br /&gt;
&lt;br /&gt;
// TODO :: дописать решение (мой код : https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220Bw29IKNdcznCYnVFbVo2alZiSzA%22]})&lt;br /&gt;
&lt;br /&gt;
== Варианты реализации ==&lt;br /&gt;
// TODO :: написать про то, что можно хранить предков (+память О(n), - скорость, - ничего нельзя сделать), а можно для каждой вершины - массив содержащих ее центроидов (+скорость(кэш), +масштабируемость(структуры данных на путях), - память n*logn)&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;/div&gt;</summary>
		<author><name>217.66.157.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=61577</id>
		<title>Centroid decomposition</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Centroid_decomposition&amp;diff=61577"/>
				<updated>2017-06-14T10:43:34Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.157.37: /* Статическая центроидная декомпозиция */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Centroid decomposition (рус. центроидная декомпозиция) - это структура данных, позволяющая отвечать на запросы на дереве. Чаще всего это запросы, связанные с нахождением функции на вершинах, связанных неравенством на расстояние между ними в дереве. Также иногда применяется для запросов на путях в дереве.&lt;br /&gt;
&lt;br /&gt;
== Введение ==&lt;br /&gt;
Рассмотрим 2 задачи на обычном массиве (в дальнейшем мы будем их обобщать на случай дерева):&lt;br /&gt;
&lt;br /&gt;
Задача 1&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_{i=0}^{n - 1} a_i \leqslant W&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
Задача 2:&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;
Первая задача решается методом [[Сортировка_слиянием|qevide&amp;amp;conqure (рус. разделяй и властвуй)]] - давайте разделим массив &amp;lt;tex&amp;gt;a[0...n-1]&amp;lt;/tex&amp;gt; на 2 массива &amp;lt;tex&amp;gt;a[0...\frac{n}{2} - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a[\frac{n}{2}...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; \frac{n}{2}, j \geqslant \frac{n}{2}&amp;lt;/tex&amp;gt;. Для этого воспользуемся другой известной техникой - методом двух указателей. Посчитаем массив префиксных сумм для правой половины &amp;lt;tex&amp;gt;pref[i] = \sum_{j=\frac{n}{2}}^{i} a_j&amp;lt;/tex&amp;gt; и суффиксных (&amp;lt;tex&amp;gt;suf[i] = \sum_{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 = \frac{n}{2} - l + 1, p_2 = \frac{n}{2}&amp;lt;/tex&amp;gt;. Пока &amp;lt;tex&amp;gt;p_2 - 1&amp;gt; \frac{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 - \frac{n}{2} + 1) * (\frac{n}{2} - p_1)&amp;lt;/math&amp;gt;, посго, увеличим &amp;lt;math&amp;gt;p_1&amp;lt;/math&amp;gt; на &amp;lt;math/math&amp;gt;. Так будем делать, пока &amp;lt;math&amp;gt;p_1 &amp;lt; \frac{n}{2}&amp;lt;/math&amp;gt;. В конце сложим текущий ответ и ответы для половин массива - получим ответ на задачу. Асимптотика такого алгоритма : &amp;lt;tex&amp;gt;T(n) = 2 * T(n / 2) + O(n) = O(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вторая задача имеет запросы на изменение и поэтому надо применить динамическую версию qevide&amp;amp;conqure - [[Дерево_отрезков._Построение|дерево отрезков]]. Построим дерево отрезков,&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;, если в i-м городе принимает госпиталь и &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;) Бинарным поиском ищем ближайший слева и ближайший справа к i-му городу госпиталь (такой город &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 &amp;gt;= 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; по сумме весов.&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,..., 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 \frac{n}{2}&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;n&amp;lt;/math&amp;gt; - размер дерева. Тогда, как и в упрощенной версии задачи - рекурсивно найдем ответ для всех поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,..., 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 * 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;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
В любом дереве t существует центроид.&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; и продолжим выбор нового u, иначе - остановимся. Докажем, что мы в какой-то момент остановимся. Пусть в призвольный момент времени &amp;lt;math&amp;gt;v&amp;lt;/math&amp;gt; - не центроид и размер её наддерева меньше &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;, значит максимальное поддерево имеет размер больше чем &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;, т.е. &amp;lt;math&amp;gt;|subtree(u)| &amp;gt; \frac{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; \frac{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;). По индукции получаем, что в любой момент времени размер наддерева вершины v меньше &amp;lt;math&amp;gt;\frac{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;
  '''int''' &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;('''int[]''' children[n], '''int''' v, '''int''' sz[n])&lt;br /&gt;
     max_subtree = -1&lt;br /&gt;
     '''for''' u : children(v)&lt;br /&gt;
          '''if''' sz[u] &amp;gt; sz[v] / 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)&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[n])&lt;br /&gt;
     c = &amp;lt;tex&amp;gt;\mathtt{findCentroid}&amp;lt;/tex&amp;gt;(children, max_subtree, sz) &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;// удаляем все ребра между вершиной с и детьми, чтобы мы не смогли из детей попасть в с. Это полезно делать, если решение  подзадачи для поддерева предполагает проход dfs &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;
Теперь вернемся ко второй задаче введения. Для ее решения мы пользовались динамичекой версией devide&amp;amp;conqure - деревом отрезков. В предыдущем пункте мы определили статический оналог devide&amp;amp;conqure для дерева. Теперь обобщим этот метод для динамических задач.&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&amp;quot;Деревом центроидов (или центроидной декомпозицией)&amp;quot; дерева &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;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,..., t_k&amp;lt;/tex&amp;gt;, а центроиды этих поддеревьев - вершины &amp;lt;tex&amp;gt;c_1, c_2, ..., c_k&amp;lt;/tex&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;c_1, c_2,..., c_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Рекурсивно перейдем к построению для поддеревьев &amp;lt;tex&amp;gt;t_1, t_2,..., 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;
|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;\frac{|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; т.и т.т., когда c - отец вершины &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; (свойство 2), то она лежит на каком-то пути в дереве &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt;, причем все ее родители (центроиды) ее содержат. А по свойству 1 длина любого вертикального (и даже простого) пути есть &amp;lt;math&amp;gt;O(log(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; мы можем решить задачу 2 для дерева :&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Есть страна, &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt; городов которой связаны двустронними дорогами, причем так, чтобы получился минимальный связный граф на &amp;lt;math&amp;gt;n-1&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; хочет узнать номер ближайшего города, госпиталь которого открыт.&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;,&lt;br /&gt;
&lt;br /&gt;
// TODO :: дописать решение (мой код : https://drivenotepad.github.io/app/?state={%22action%22:%22open%22,%22ids%22:[%220Bw29IKNdcznCYnVFbVo2alZiSzA%22]})&lt;br /&gt;
&lt;br /&gt;
== Варианты реализации ==&lt;br /&gt;
// TODO :: написать про то, что можно хранить предков (+память О(n), - скорость, - ничего нельзя сделать), а можно для каждой вершины - массив содержащих ее центроидов (+скорость(кэш), +масштабируемость(структуры данных на путях), - память n*logn)&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;/div&gt;</summary>
		<author><name>217.66.157.37</name></author>	</entry>

	</feed>