<?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=6yry6e</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=6yry6e"/>
		<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/6yry6e"/>
		<updated>2026-08-03T23:04:27Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52092</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52092"/>
				<updated>2016-01-28T20:43:10Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: /* Источники информации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
  '''int''' dfs('''int''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, '''int''' flow) &lt;br /&gt;
    '''if''' (flow == 0) &lt;br /&gt;
      '''return''' 0&lt;br /&gt;
    '''if''' (&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; == &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      '''return''' flow&lt;br /&gt;
    '''for''' (&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; = ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;] '''to''' n)&lt;br /&gt;
      ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;]++&lt;br /&gt;
      '''if''' (&amp;lt;tex&amp;gt;vu \in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
        pushed = dfs(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, min(flow, c(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) - f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;)))&lt;br /&gt;
        f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) += pushed&lt;br /&gt;
        f(&amp;lt;tex&amp;gt;uv&amp;lt;/tex&amp;gt;) -= pushed&lt;br /&gt;
        '''return''' pushed&lt;br /&gt;
    '''return''' 0&lt;br /&gt;
&lt;br /&gt;
  '''main'''()&lt;br /&gt;
    '''...'''&lt;br /&gt;
    flow = 0&lt;br /&gt;
    '''for''' ('''int''' i = 1 '''to''' n)&lt;br /&gt;
      ptr[i] = 0&lt;br /&gt;
    '''do'''&lt;br /&gt;
      pushed = dfs(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      flow += pushed&lt;br /&gt;
    '''while''' (pushed &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [http://e-maxx.ru/algo/dinic  MAXimal :: algo :: Алгоритм Диница]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52091</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52091"/>
				<updated>2016-01-28T20:37:19Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
  '''int''' dfs('''int''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, '''int''' flow) &lt;br /&gt;
    '''if''' (flow == 0) &lt;br /&gt;
      '''return''' 0&lt;br /&gt;
    '''if''' (&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; == &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      '''return''' flow&lt;br /&gt;
    '''for''' (&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; = ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;] '''to''' n)&lt;br /&gt;
      ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;]++&lt;br /&gt;
      '''if''' (&amp;lt;tex&amp;gt;vu \in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
        pushed = dfs(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, min(flow, c(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) - f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;)))&lt;br /&gt;
        f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) += pushed&lt;br /&gt;
        f(&amp;lt;tex&amp;gt;uv&amp;lt;/tex&amp;gt;) -= pushed&lt;br /&gt;
        '''return''' pushed&lt;br /&gt;
    '''return''' 0&lt;br /&gt;
&lt;br /&gt;
  '''main'''()&lt;br /&gt;
    '''...'''&lt;br /&gt;
    flow = 0&lt;br /&gt;
    '''for''' ('''int''' i = 1 '''to''' n)&lt;br /&gt;
      ptr[i] = 0&lt;br /&gt;
    '''do'''&lt;br /&gt;
      pushed = dfs(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      flow += pushed&lt;br /&gt;
    '''while''' (pushed &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://www.e-maxx.ru/algo/dinic Алгоритм Диница. Необходимые определения.]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52090</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52090"/>
				<updated>2016-01-28T20:35:31Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
  '''int''' dfs('''int''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, '''int''' flow) &lt;br /&gt;
    '''if''' (flow == 0) &lt;br /&gt;
      '''return''' 0&lt;br /&gt;
    '''if''' (&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; == &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      '''return''' flow&lt;br /&gt;
    '''for''' (&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; = ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;] '''to''' n)&lt;br /&gt;
      ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;]++&lt;br /&gt;
      '''if''' (&amp;lt;tex&amp;gt;vu \in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      pushed = dfs(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, min(flow, c(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) - f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;)))&lt;br /&gt;
      f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) += pushed&lt;br /&gt;
      f(&amp;lt;tex&amp;gt;uv&amp;lt;/tex&amp;gt;) -= pushed&lt;br /&gt;
      '''return''' pushed&lt;br /&gt;
    '''return''' 0&lt;br /&gt;
&lt;br /&gt;
  '''main'''()&lt;br /&gt;
    '''...'''&lt;br /&gt;
    flow = 0&lt;br /&gt;
    '''for''' ('''int''' i = 1 '''to''' n)&lt;br /&gt;
        ptr[i] = 0&lt;br /&gt;
    '''do'''&lt;br /&gt;
      pushed = dfs(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      flow += pushed&lt;br /&gt;
    '''while''' (pushed &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://www.e-maxx.ru/algo/dinic Алгоритм Диница. Необходимые определения.]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52089</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52089"/>
				<updated>2016-01-28T20:32:15Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
  '''int''' dfs('''int''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, '''int''' flow) &lt;br /&gt;
    '''if''' (flow == 0) &lt;br /&gt;
      '''return''' 0&lt;br /&gt;
    '''if''' (&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; == &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      '''return''' flow&lt;br /&gt;
    '''for''' (&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; = ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;] '''to''' n)&lt;br /&gt;
      ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;]++&lt;br /&gt;
     '''if''' (&amp;lt;tex&amp;gt;vu \in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       pushed = dfs(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, min(flow, c(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) - f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;)))&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) += pushed&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;uv&amp;lt;/tex&amp;gt;) -= pushed&lt;br /&gt;
       '''return''' pushed&lt;br /&gt;
   '''return''' 0&lt;br /&gt;
&lt;br /&gt;
  '''main'''()&lt;br /&gt;
    '''...'''&lt;br /&gt;
    flow = 0&lt;br /&gt;
    '''for''' ('''int''' i = 1 '''to''' n)&lt;br /&gt;
        ptr[i] = 0&lt;br /&gt;
    '''do'''&lt;br /&gt;
      pushed = dfs(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      flow += pushed&lt;br /&gt;
    '''while''' (pushed &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://www.e-maxx.ru/algo/dinic Алгоритм Диница. Необходимые определения.]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52088</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52088"/>
				<updated>2016-01-28T20:30:37Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
  '''int''' dfs('''int''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, '''int''' flow) &lt;br /&gt;
    '''if''' (flow == 0) &lt;br /&gt;
      '''return''' 0&lt;br /&gt;
    '''if''' (&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; == &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      '''return''' flow&lt;br /&gt;
    '''for''' (&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; = ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;] '''to''' n)&lt;br /&gt;
    ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;]++&lt;br /&gt;
     '''if''' (&amp;lt;tex&amp;gt;vu \in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       pushed = dfs(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, min(flow, c(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) - f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;)))&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) += pushed&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;uv&amp;lt;/tex&amp;gt;) -= pushed&lt;br /&gt;
       '''return''' pushed&lt;br /&gt;
   '''return''' 0&lt;br /&gt;
&lt;br /&gt;
  '''main'''()&lt;br /&gt;
    '''...'''&lt;br /&gt;
    flow = 0&lt;br /&gt;
    '''for''' ('''int''' i = 1 '''to''' n)&lt;br /&gt;
        ptr[i] = 0&lt;br /&gt;
    '''do'''&lt;br /&gt;
      pushed = dfs(&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      flow += pushed&lt;br /&gt;
    '''while''' (pushed &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://www.e-maxx.ru/algo/dinic Алгоритм Диница. Необходимые определения.]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52085</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52085"/>
				<updated>2016-01-28T20:21:49Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
 '''int''' dfs('''int''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, '''int''' flow) &lt;br /&gt;
   '''if''' (flow == 0) &lt;br /&gt;
     '''return''' 0&lt;br /&gt;
   '''if''' (&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; == &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
     '''return''' flow&lt;br /&gt;
   '''for''' (&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; = ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;] '''to''' n) &amp;lt;font color=darkgreen&amp;gt; // u - ссылочный тип&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''if''' (&amp;lt;tex&amp;gt;vu \in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       pushed = dfs(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, min(flow, c(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) - f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;)));&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) += pushed&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;uv&amp;lt;/tex&amp;gt;) -= pushed&lt;br /&gt;
       '''return''' pushed&lt;br /&gt;
   '''return''' 0&lt;br /&gt;
&lt;br /&gt;
  '''main'''( )&lt;br /&gt;
    '''...'''&lt;br /&gt;
    flow = 0&lt;br /&gt;
    '''for''' ('''int''' i = 1 '''to''' n)&lt;br /&gt;
      ptr[i] = 0;&lt;br /&gt;
    '''do'''&lt;br /&gt;
      pushed = '''dfs''' (&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      flow += pushed;&lt;br /&gt;
    '''while''' (pushed &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://www.e-maxx.ru/algo/dinic Алгоритм Диница. Необходимые определения.]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52084</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52084"/>
				<updated>2016-01-28T20:19:46Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
 '''int''' dfs('''int''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, '''int''' flow) &lt;br /&gt;
   '''if''' (flow == 0) &lt;br /&gt;
     '''return''' 0&lt;br /&gt;
   '''if''' (&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; == &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
     '''return''' flow&lt;br /&gt;
   '''for''' (&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; = ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;] '''to''' n) &amp;lt;font color=darkgreen&amp;gt; // u - ссылочный тип&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''if''' (&amp;lt;tex&amp;gt;vu \in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       pushed = dfs(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, min(flow, c(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) - f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;)));&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) += pushed&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;uv&amp;lt;/tex&amp;gt;) -= pushed&lt;br /&gt;
       '''return''' pushed&lt;br /&gt;
   '''return''' 0&lt;br /&gt;
&lt;br /&gt;
  '''main'''( )&lt;br /&gt;
    '''...'''&lt;br /&gt;
    flow = 0&lt;br /&gt;
    '''for''' ('''int''' i = 0 '''to''' n)&lt;br /&gt;
      ptr[i] = 0;&lt;br /&gt;
    '''do'''&lt;br /&gt;
      pushed = '''dfs''' (&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      flow += pushed;&lt;br /&gt;
    '''while''' (pushed &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://www.e-maxx.ru/algo/dinic Алгоритм Диница. Необходимые определения.]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52083</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52083"/>
				<updated>2016-01-28T20:19:04Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: отступы в псевдокоде&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
 '''int''' dfs('''int''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, '''int''' flow) &lt;br /&gt;
   '''if''' (flow == 0) &lt;br /&gt;
     '''return''' 0&lt;br /&gt;
   '''if''' (&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; == &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
     '''return''' flow&lt;br /&gt;
   '''for''' (&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; = ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;] '''to''' n) &amp;lt;font color=darkgreen&amp;gt; // u - ссылочный тип&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''if''' (&amp;lt;tex&amp;gt;vu \in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
       pushed = dfs(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, min(flow, c(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) - f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;)));&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) += pushed&lt;br /&gt;
       f(&amp;lt;tex&amp;gt;uv&amp;lt;/tex&amp;gt;) -= pushed&lt;br /&gt;
       '''return''' pushed&lt;br /&gt;
   '''return''' 0&lt;br /&gt;
&lt;br /&gt;
  '''main'''( )&lt;br /&gt;
    '''...'''&lt;br /&gt;
    flow = 0&lt;br /&gt;
    '''for''' ('''int''' i = 0 '''to''' n)&lt;br /&gt;
      ptr[i] = 0;&lt;br /&gt;
      '''do'''&lt;br /&gt;
        pushed = '''dfs''' (&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;)&lt;br /&gt;
        flow += pushed;&lt;br /&gt;
      '''while''' (pushed &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://www.e-maxx.ru/algo/dinic Алгоритм Диница. Необходимые определения.]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52082</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52082"/>
				<updated>2016-01-28T20:08:28Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: оформление&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
 '''int''' dfs('''int''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, '''int''' flow) &lt;br /&gt;
  '''if''' (flow == 0) &lt;br /&gt;
    '''return''' 0&lt;br /&gt;
  '''if''' (&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; == &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''return''' flow&lt;br /&gt;
  '''for''' (&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; = ptr[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;] '''to''' n) &amp;lt;font color=darkgreen&amp;gt; // u - ссылочный тип&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''if''' (&amp;lt;tex&amp;gt;vu \in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      pushed = dfs(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, min(flow, c(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) - f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;)));&lt;br /&gt;
      f(&amp;lt;tex&amp;gt;vu&amp;lt;/tex&amp;gt;) += pushed&lt;br /&gt;
      f(&amp;lt;tex&amp;gt;uv&amp;lt;/tex&amp;gt;) -= pushed&lt;br /&gt;
      '''return''' pushed&lt;br /&gt;
  '''return''' 0&lt;br /&gt;
&lt;br /&gt;
  '''main'''( )&lt;br /&gt;
    '''...'''&lt;br /&gt;
    flow = 0&lt;br /&gt;
    '''for''' ('''int''' i = 0 '''to''' n)&lt;br /&gt;
      ptr[i] = 0;&lt;br /&gt;
    '''do'''&lt;br /&gt;
      pushed = '''dfs''' (&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      flow += pushed;&lt;br /&gt;
    '''while''' (pushed &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Блокирующий поток]]&lt;br /&gt;
* [[Схема алгоритма Диница]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
*[http://www.e-maxx.ru/algo/dinic Алгоритм Диница. Необходимые определения.]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52078</id>
		<title>Алгоритм поиска блокирующего потока в ациклической сети</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B5%D0%B3%D0%BE_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0_%D0%B2_%D0%B0%D1%86%D0%B8%D0%BA%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B9_%D1%81%D0%B5%D1%82%D0%B8&amp;diff=52078"/>
				<updated>2016-01-28T19:32:15Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: изменен псевдокод и исправлены опечатки&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Жадный алгоритм==&lt;br /&gt;
Идея заключается в том, чтобы по одному находить пути из [[Определение_сети,_потока|истока]] &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в [[Определение_сети,_потока|сток]] &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, пока это возможно. [[Обход в глубину, цвета вершин| Обход в глубину]] найдёт все пути из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, если из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; достижима &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а [[Определение_сети,_потока|пропускная способность]] каждого ребра &amp;lt;tex&amp;gt;c(u, v)&amp;gt;0&amp;lt;/tex&amp;gt; поэтому, насыщая рёбра, мы хотя бы единожды достигнем стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, следовательно блокирующий поток всегда найдётся.&lt;br /&gt;
&lt;br /&gt;
Используя &amp;lt;tex&amp;gt;dfs&amp;lt;/tex&amp;gt;, каждый путь находится за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; — число рёбер в графе. Поскольку каждый путь насыщает как минимум одно ребро, всего будет &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt; путей. Итого общая асимптотика составляет &amp;lt;tex&amp;gt;O(E^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Удаляющий обход==&lt;br /&gt;
Аналогично предыдущей идее, однако будем удалять в процессе обхода в глубину из графа все рёбра, вдоль которых не получится дойти до стока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Это очень легко реализовать: достаточно удалять ребро после того, как мы просмотрели его в обходе в глубину (кроме того случая, когда мы прошли вдоль ребра и нашли путь до стока). С точки зрения реализации, надо просто поддерживать в списке смежности каждой вершины указатель на первое не удалённое ребро, и увеличивать этот указать в цикле внутри обхода в глубину. Корректность при этом сохраняется согласно предыдущему пункту. &lt;br /&gt;
&lt;br /&gt;
 '''dfs''' (''v'', ''flow'') &lt;br /&gt;
  '''if''' (''flow'' == 0) &lt;br /&gt;
    '''return''' 0;&lt;br /&gt;
  '''if''' (''v'' == '''t''')&lt;br /&gt;
    '''return''' ''flow'';&lt;br /&gt;
  '''for''' (''u'' = ptr[''v''] '''to''' n) // ''u'' is reference value&lt;br /&gt;
    '''if''' (''vu'' &amp;lt;tex&amp;gt;\in E&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      pushed = '''dfs''' (''u'', min (flow, c(''vu'') - f(''vu'')));&lt;br /&gt;
      f(''vu'') += pushed;&lt;br /&gt;
      f(''uv'') -= pushed;&lt;br /&gt;
      '''return''' pushed;&lt;br /&gt;
  '''return''' 0;&lt;br /&gt;
&lt;br /&gt;
  '''main''' ( )&lt;br /&gt;
    '''...'''&lt;br /&gt;
    ''flow'' = 0;&lt;br /&gt;
    ptr[''i''] = 0, ''i'' = ''1...n'';&lt;br /&gt;
    '''while''' (pushed = '''dfs''' ('''s''', ''INF''))&lt;br /&gt;
      ''flow'' += pushed;&lt;br /&gt;
&lt;br /&gt;
Если обход в глубину достигает стока, насыщается как минимум одно ребро, иначе как минимум один указатель продвигается вперед. Значит один запуск обхода в глубину работает за &amp;lt;tex&amp;gt;O(V + K)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt; — число вершин в графе, а &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; — число продвижения указателей. Ввиду того, что всего запусков обхода в глубину в рамках поиска одного [[Блокирующий поток|блокирующего потока]] будет &amp;lt;tex&amp;gt;O(P)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; — число рёбер, насыщенных этим блокирующим потоком, то весь алгоритм поиска блокирующего потока отработает за &amp;lt;tex&amp;gt;O(PV + \sum\limits_i{K_i})&amp;lt;/tex&amp;gt;, что, учитывая, что все указатели в сумме прошли расстояние &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;, дает асимптотику &amp;lt;tex&amp;gt;O(PV + E)&amp;lt;/tex&amp;gt;. В худшем случае, когда блокирующий поток насыщает все ребра, асимптотика получается &amp;lt;tex&amp;gt;O(VE)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Замечание:&amp;lt;/b&amp;gt; Если в [[Схема алгоритма Диница|алгоритме Диница]] искать блокирующий поток удаляющим обходом, то его эффективность составит &amp;lt;tex&amp;gt;O(V^2E)&amp;lt;/tex&amp;gt;, что уже лучше эффективности [[Алоритм Эдмондса-Карпа|алгоритма Эдмондса-Карпа]] &amp;lt;tex&amp;gt;O(VE^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Малхотры — Кумара — Махешвари==&lt;br /&gt;
===Идея===&lt;br /&gt;
Для каждой вершины  вводится потенциал потока, равный максимальному дополнительному потоку, который может пройти через эту вершину. Далее запускаем цикл, на каждой итерации которого определяем вершину &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальным потенциалом &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Затем пускается поток величины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; из истока в сток, проходящий через эту вершину. При этом если [[Дополняющая сеть, дополняющий путь|остаточная пропускная способность]] ребра равна нулю, то это ребро удаляется. Также, удаляются все вершины, у которых не остаётся ни одного входящего и/или ни одного выходящего ребра. При удалении вершины все смежные ребра удаляются.&lt;br /&gt;
&lt;br /&gt;
===Подробное описание===&lt;br /&gt;
* Для каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислим входящий и исходящий потенциал: &amp;lt;tex&amp;gt;p_{in}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}=\sum \limits_{u} c(u, v)&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p_{in}(s)=\infty&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{out}(t)=\infty&amp;lt;/tex&amp;gt;. Определим потенциал или пропускную способность вершины в [[Определение сети, потока|сети]] &amp;lt;tex&amp;gt;p(v)=min(p_{in}(v), p_{out}(v))&amp;lt;/tex&amp;gt;. Таким образом, потенциал вершины определяет максимально возможное количество потока, который может через нее проходить. Ясно, что через вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt; поток проходить не может. Следовательно, их можно удалить из [[Дополняющая сеть, дополняющий путь|вспомогательной сети]]. Удалим эти вершины и дуги, им инцидентные, обновив должным образом потенциалы вершин, смежных с удаленными. Если в результате появятся новые вершины с &amp;lt;tex&amp;gt;p(v)=0&amp;lt;/tex&amp;gt;, удалим рекурсивно и их. В результате во вспомогательной сети останутся только вершины с &amp;lt;tex&amp;gt;p(v)\ne0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* После этого приступим к построению [[Блокирующий поток|блокирующего потока]]. Пусть вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; принадлежит &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ому слою и &amp;lt;tex&amp;gt;p(v)=min (p(w), w \in L_k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;L_k&amp;lt;/tex&amp;gt;  —  &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-й слой. Протолкнем &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; единиц потока из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в смежные с ней вершины по исходящим дугам с [[Дополняющая сеть, дополняющий путь | остаточной пропускной способностью]] &amp;lt;tex&amp;gt;c_f \ne 0&amp;lt;/tex&amp;gt;. Попутно будем переносить проталкиваемый поток в исходную сеть, а также корректировать потенциалы вершин, отправляющих и принимающих избыток потока. В результате, весь (в виду минимальности потенциала вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;) проталкиваемый поток соберется в вершинах &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя. &lt;br /&gt;
&lt;br /&gt;
* Повторим процесс отправки потока из вершин &amp;lt;tex&amp;gt;(k+1)&amp;lt;/tex&amp;gt;-го слоя, содержащих избыток потока, в смежные им вершины &amp;lt;tex&amp;gt;(k+2)&amp;lt;/tex&amp;gt;-го слоя. И так до тех пор, пока весь поток не соберется в последнем слое, в котором содержится только сток &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, ибо все остальные вершины, ранее ему принадлежащие, были удалены, поскольку их потенциалы нулевые. Следовательно, весь поток величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленный из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный полностью соберется в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
* На втором этапе вновь, начиная с вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, осуществляется подвод потока уже по входящим дугам. В результате на первом шаге недостаток потока переадресуется к узлам &amp;lt;tex&amp;gt;(k-1)&amp;lt;/tex&amp;gt;-го слоя, затем &amp;lt;tex&amp;gt;(k-2)&amp;lt;/tex&amp;gt;-го. И так до тех пор, пока весь потока величины &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt;, отправленные из вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p(v)&amp;lt;/tex&amp;gt; - минимальный, не соберется в истоке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, поток и во вспомогательной и в основной сети увеличится на величину &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 MPM algorithm(&amp;lt;tex&amp;gt;s, t&amp;lt;/tex&amp;gt;)&lt;br /&gt;
 {&lt;br /&gt;
    foreach &amp;lt;tex&amp;gt;(uv) \in E&amp;lt;/tex&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;f(uv) \leftarrow 0 &amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Вычисляем остаточную сеть &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    Найдём вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    while (&amp;lt;tex&amp;gt;t \in L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    {&lt;br /&gt;
      while (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; достижима из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      {&lt;br /&gt;
        найдём &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; с минимальной пропускной способностью &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        проталкиваем &amp;lt;tex&amp;gt;g&amp;lt;/tex&amp;gt; единиц потока из &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;;&lt;br /&gt;
        изменяем &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
      }&lt;br /&gt;
      вычисляем новый вспомогательный граф &amp;lt;tex&amp;gt;L&amp;lt;/tex&amp;gt; из &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Если информация о входящих и исходящих дугах будет храниться в виде связных списков, то для того, чтобы пропустить поток, на каждой итерации будет выполнено &amp;lt;tex&amp;gt;O(K + E_i)&amp;lt;/tex&amp;gt; действий, где &amp;lt;tex&amp;gt;K&amp;lt;/tex&amp;gt; соответствует числу рёбер, для которых остаточная пропускная способность уменьшилась, но осталась положительной, а &amp;lt;tex&amp;gt;E_i&amp;lt;/tex&amp;gt; — числу удалённых ребер. Таким образом, для поиска блокирующего потока будет выполнено &amp;lt;tex&amp;gt;\sum\limits_i{O(K+E_i)} = O(K^2)&amp;lt;/tex&amp;gt; действий.&lt;br /&gt;
&lt;br /&gt;
==Источники==&lt;br /&gt;
*[http://e-maxx.ru/algo/dinic#8 e-maxx Алгоритм Диница]&lt;br /&gt;
*[http://www.facweb.iitkgp.ernet.in/~arijit/courses/autumn2006/cs60001/lec-flow-4.pdf The MPM Algorithm]&lt;br /&gt;
*[http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BB%D1%85%D0%BE%D1%82%D1%80%D1%8B_%E2%80%94_%D0%9A%D1%83%D0%BC%D0%B0%D1%80%D0%B0_%E2%80%94_%D0%9C%D0%B0%D1%85%D0%B5%D1%88%D0%B2%D0%B0%D1%80%D0%B8 Алгоритм Малхотры — Кумара — Махешвари]&lt;br /&gt;
*[http://eprints.utas.edu.au/160/1/iplFlow.pdf Оригинальная публикация алгоритма Малхотры — Кумара — Махешвари.]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Задача о максимальном потоке]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%A5%D0%B0%D0%BD%D0%B0&amp;diff=48069</id>
		<title>Сортировка Хана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%A5%D0%B0%D0%BD%D0%B0&amp;diff=48069"/>
				<updated>2015-06-07T21:14:45Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка Хана''' (англ. ''Hansort'') {{---}} сложный алгоритм сортировки целых чисел со сложностью &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов для сортировки.&lt;br /&gt;
&lt;br /&gt;
Данная статья писалась на основе брошюры Хана (англ. ''Yijie Han''), посвященной этой сортировке.&lt;br /&gt;
&lt;br /&gt;
== Описание ==&lt;br /&gt;
Алгоритм построен на основе '''экспоненциального поискового дерева Андерсона''' (англ. ''Andersson's exponential search tree''). Сортировка происходит за счет вставки целых чисел в экспоненциальное поисковое дерево (''далее {{---}} ЭП-дерево'').&lt;br /&gt;
&lt;br /&gt;
== Экспоненциальное поисковое дерево Андерсона ==&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = '''ЭП-дерево''' {{---}} это дерево поиска, в котором все ключи хранятся в листьях этого дерева и количество детей у каждого узла уменьшается экспоненциально от глубины узла.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Файл:Exp-tree.png|400px|thumb|right|Общая структура ЭП-дерева]]&lt;br /&gt;
&lt;br /&gt;
Структура ЭП-дерева:&lt;br /&gt;
&lt;br /&gt;
1) Корень имеет &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\Theta (n^e)&amp;lt;/tex&amp;gt; сыновей &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;( 0 &amp;lt; e &amp;lt; 1 )&amp;lt;/tex&amp;gt;. Все сыновья являются ЭП-деревьями.&lt;br /&gt;
&lt;br /&gt;
2) Каждое поддерево корня имеет &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\Theta(n^{1-e})&amp;lt;/tex&amp;gt; сыновей.&lt;br /&gt;
&lt;br /&gt;
В этом дереве &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; уровней. При нарушении баланса дерева необходимо балансирование, которое требует &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; времени при &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; вставленных целых числах. Такое время достигается за счет вставки чисел группами, а не поодиночке, как изначально предлагал Андерссон.&lt;br /&gt;
&lt;br /&gt;
==Определения== &lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 '''Контейнер''' {{---}} объект, в которым хранятся наши данные. Например: 32-битные и 64-битные числа, массивы, вектора.}}&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Алгоритм, сортирующий &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел из множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt;, называется '''консервативным''', если длина контейнера (число бит в контейнере) равна &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log(m + n))&amp;lt;/tex&amp;gt;. Если длина больше, то алгоритм '''неконсервативный'''.&lt;br /&gt;
 }}&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Если сортируются целые числа из множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt; с длиной контейнера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log (m + n)&amp;lt;/tex&amp;gt; с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \geqslant 1&amp;lt;/tex&amp;gt;, тогда сортировка происходит с '''неконсервативным преимуществом''' &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Для множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; определим&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\min(S) = \min\limits_{a \in S} a&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\max(S) = \max\limits_{a \in S} a&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S1 &amp;lt; S2&amp;lt;/tex&amp;gt; если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\max(S1) \leqslant \min(S2)&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Предположим, есть набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел, которые уже отсортированы как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}, a_{2}, \ldots, a_{p}&amp;lt;/tex&amp;gt; и набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{1}, b_{2}, \ldots, b_{q}&amp;lt;/tex&amp;gt;. Тогда '''разделением''' &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; числами называется &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0}, S_{1}, \ldots, S_{p}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; a_{1} &amp;lt; S_{1} &amp;lt; \ldots &amp;lt; a_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Леммы==&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma1&lt;br /&gt;
|about = № 1&lt;br /&gt;
|statement = &lt;br /&gt;
Даны целые числа &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b \geqslant s \geqslant 0&amp;lt;/tex&amp;gt;, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; является подмножеством множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, \ldots, 2^b - 1\}&amp;lt;/tex&amp;gt;, содержащим &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; элементов, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t \geqslant 2^{-s + 1}С^k_{n}&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}&amp;lt;/tex&amp;gt;, принадлежащая &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;H_{b,s}&amp;lt;/tex&amp;gt;, может быть выбрана за время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(bn^2)&amp;lt;/tex&amp;gt; так, что количество коллизий &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;coll(h_{a}, T) \leqslant t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma2&lt;br /&gt;
|about = № 2&lt;br /&gt;
|statement = &lt;br /&gt;
Выбор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;-ого наибольшего числа среди &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел, упакованных в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнеров, может быть сделан за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log g}{g})&amp;lt;/tex&amp;gt; и с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти. В том числе, так  может быть найдена медиана.&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Так как возможно делать попарное сравнение &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел в одном контейнере с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; числами в другом и извлекать большие числа из одного контейнера и меньшие из другого за константное время, возможно упаковать медианы из первого, второго, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;-ого чисел из 5 контейнеров в один контейнер за константное время. Таким образом, набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; из медиан теперь содержится в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{5g}&amp;lt;/tex&amp;gt; контейнерах. Рекурсивно находим медиану &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;m&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;. Используя &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;m&amp;lt;/tex&amp;gt;, уберем хотя бы &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{4}&amp;lt;/tex&amp;gt; чисел среди &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt;. Затем упакуем оставшиеся из &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнеров в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{3n}{4g}&amp;lt;/tex&amp;gt; контейнеров и затем продолжим рекурсию.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma3&lt;br /&gt;
|about = № 3&lt;br /&gt;
|statement = &lt;br /&gt;
Если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; целых чисел, в сумме использующих &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит, упакованы в один контейнер, тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнерах могут быть отсортированы за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log g}{g})&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Так как используется только &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит в каждом контейнере для хранения &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел, используем bucket sort, чтобы отсортировать все контейнеры, представляя каждый как число, что занимает &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; времени и памяти. Так как используется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит на контейнер, понадобится &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; шаблонов для всех контейнеров. Затем поместим &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;g &amp;lt; \frac{\log n}{2}&amp;lt;/tex&amp;gt; контейнеров с одинаковым шаблоном в одну группу. Для каждого шаблона останется не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g - 1&amp;lt;/tex&amp;gt; контейнеров, которые не смогут образовать группу. Поэтому не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}(g - 1)&amp;lt;/tex&amp;gt; контейнеров не смогут сформировать группу. Для каждой группы помещаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-е число во всех &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнерах в один. Таким образом берутся &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;-целых векторов и получаются &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;-целых векторов, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ый вектор содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ое число из входящего вектора. Эта транспозиция может быть сделана за время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(g \log g)&amp;lt;/tex&amp;gt;, с использованием &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(g)&amp;lt;/tex&amp;gt; памяти. Для всех групп это занимает время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log g}{g})&amp;lt;/tex&amp;gt;, с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
Для контейнеров вне групп (которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}(g - 1)&amp;lt;/tex&amp;gt; штук) разбираем и собираем заново контейнеры. На это потребуется не более &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; времени и памяти. После всего этого используем карманную сортировку вновь для сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; контейнеров. Таким образом, все числа отсортированы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заметим, что когда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g = O( \log n)&amp;lt;/tex&amp;gt;, сортировка &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнеров произойдет за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O((\frac{n}{g})&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n)&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти. Выгода очевидна.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma4&lt;br /&gt;
|about = № 4&lt;br /&gt;
|statement = &lt;br /&gt;
Примем, что каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt; \log m &amp;gt; \log n&amp;lt;/tex&amp;gt; бит, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{g}&amp;lt;/tex&amp;gt; бит, упакованы в один контейнер. Если каждое число имеет маркер, содержащий &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2g}&amp;lt;/tex&amp;gt; бит, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; маркеров упакованы в один контейнер таким же образом&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;^*&amp;lt;/tex&amp;gt;, что и числа, тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнерах могут быть отсортированы по их маркерам за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log\log n}{g})&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
(*): если число &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; упаковано как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;-ое число в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt;-ом контейнере для чисел, тогда маркер для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; упакован как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;-ый маркер в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt;-ом контейнере для маркеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Контейнеры для маркеров могут быть отсортированы с помощью bucket sort потому, что каждый контейнер использует &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит. Сортировка сгруппирует контейнеры для чисел как в [[#lemma3|лемме №3]]. Перемещаем каждую группу контейнеров для чисел.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma5&lt;br /&gt;
|about = № 5&lt;br /&gt;
|statement =&lt;br /&gt;
Предположим, что каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \log\log n &amp;gt; \log n&amp;lt;/tex&amp;gt; бит, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{g}&amp;lt;/tex&amp;gt; бит, упакованы в один контейнер, что каждое число имеет маркер, содержащий &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2g}&amp;lt;/tex&amp;gt; бит, и что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; маркеров упакованы в один контейнер тем же образом что и числа. Тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнерах могут быть отсортированы по своим маркерам за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Заметим, что несмотря на то, что длина контейнера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \log\log n&amp;lt;/tex&amp;gt; бит, всего &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит используется для хранения упакованных чисел. Так же как в [[#lemma3|лемме №3]] и [[#lemma4|лемме №4]] сортируем контейнеры упакованных маркеров с помощью bucket sort. Для того, чтобы перемещать контейнеры чисел, помещаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; вместо &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнеров чисел в одну группу. Для транспозиции чисел в группе, содержащей &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; контейнеров, упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; контейнеров в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;, упаковывая &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров в один. Далее делаем транспозицию над &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнерами. Таким образом перемещение занимает всего &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(g \log\log n)&amp;lt;/tex&amp;gt; времени для каждой группы и &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; времени для всех чисел. После завершения транспозиции, распаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнеров в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; контейнеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заметим, что если длина контейнера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \log\log n&amp;lt;/tex&amp;gt; и только &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит используется для упаковки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \leqslant \log n&amp;lt;/tex&amp;gt; чисел в один контейнер, тогда выбор в [[#lemma2|лемме №2]] может быть сделан за время и память &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt;, потому что упаковка в доказательстве [[#lemma2|лемме №2]] теперь может быть сделана за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma6&lt;br /&gt;
|about = № 6&lt;br /&gt;
|statement = &lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел можно отсортировать в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{\sqrt{n}}&amp;lt;/tex&amp;gt; таким образом, что в каждом наборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; чисел и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i} &amp;lt; S_{j}&amp;lt;/tex&amp;gt; при &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i &amp;lt; j&amp;lt;/tex&amp;gt;, за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log\log n} {\log k})&amp;lt;/tex&amp;gt; и место &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; с неконсервативным преимуществом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log\log n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Алгоритм сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; наборов, представленный ниже, является доказательством данной леммы. &lt;br /&gt;
&lt;br /&gt;
Постановка задачи и решение некоторых проблем:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим проблему сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел из множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; наборов, как в условии леммы. Предполагаем, что каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log\log n \log m&amp;lt;/tex&amp;gt; бит и хранит число в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит. Поэтому неконсервативное преимущество {{---}} &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log \log n&amp;lt;/tex&amp;gt;. Также предполагаем, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \geqslant \log n \log\log n&amp;lt;/tex&amp;gt;. Иначе можно использовать radix sort для сортировки за время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; и линейную память. Делим &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит, используемых для представления каждого числа, в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; блоков. Таким образом, каждый блок содержит как минимум &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; бит. &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ый блок содержит с &lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{i \log m} {\log n}&amp;lt;/tex&amp;gt;-ого по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{(i + 1) \log m} {\log n - 1})&amp;lt;/tex&amp;gt;-ый биты. Биты считаются с наименьшего бита, начиная с нуля. Теперь у нас имеется &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log n&amp;lt;/tex&amp;gt;-уровневый алгоритм, который работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На каждой стадии работаем с одним блоком бит. Назовем эти блоки маленькими числами (далее м.ч.), потому что каждое м.ч. теперь содержит только &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{\log n}&amp;lt;/tex&amp;gt; бит. Каждое число представлено и соотносится с м.ч., над которым работаем в данный момент. Положим, что нулевая стадия работает с самым большим блоком (блок номер &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n - 1&amp;lt;/tex&amp;gt;). Предполагаем, что биты этих м.ч. упакованы в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{\log n}&amp;lt;/tex&amp;gt; контейнеров с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; м.ч. упакованными в один контейнер. Пренебрегая временем, потраченным на эту упаковку, считаем, что она бесплатна. По [[#lemma2|лемме №2]] находим медиану этих &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; м.ч. за время и память &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{\log n})&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} это найденная медиана. Тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; м.ч. могут быть разделены на не более чем три группы: &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{3}&amp;lt;/tex&amp;gt;. &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt; содержит м.ч., которые меньше &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt; содержит м.ч., равные &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{3}&amp;lt;/tex&amp;gt; содержит м.ч., большие &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;. Также мощность &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{3} &amp;lt;/tex&amp;gt; не превосходит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n/2&amp;lt;/tex&amp;gt;. Мощность &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt; может быть любой. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S'_{2}&amp;lt;/tex&amp;gt; {{---}} это набор чисел, у которых наибольший блок находится в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt;. Тогда убираем из дальнейшего рассмотрения &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{\log n}&amp;lt;/tex&amp;gt; бит (наибольший блок) из каждого числа, принадлежащего &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S'_{2}&amp;lt;/tex&amp;gt;. Таким образом, после первой стадии каждое число находится в наборе размера не большего половины размера начального набора или один из блоков в числе убран из дальнейшего рассмотрения. Так как в каждом числе только &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; блоков, для каждого числа потребуется не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; стадий, чтобы поместить его в набор половинного размера. За &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log n&amp;lt;/tex&amp;gt; стадий все числа будут отсортированы. Так как на каждой стадии работаем с &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{\log n}&amp;lt;/tex&amp;gt; контейнерами, то игнорируя время, необходимое на упаковку м.ч. в контейнеры и помещение м.ч. в нужный набор, затрачивается &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени из-за &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log n&amp;lt;/tex&amp;gt; стадий.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложная часть алгоритма заключается в том, как поместить м.ч. в набор, которому принадлежит соответствующее число, после предыдущих операций деления набора в нашем алгоритме. Предположим, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел уже поделены в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;e&amp;lt;/tex&amp;gt; наборов. Используем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log e&amp;lt;/tex&amp;gt; битов чтобы сделать марки для каждого набора. Теперь используем [[#lemma5|лемме №5]]. Полный размер маркера для каждого контейнера должен быть &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt;, и маркер использует &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log e&amp;lt;/tex&amp;gt; бит, значит количество маркеров &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; в каждом контейнере должно быть не более &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2\log e}&amp;lt;/tex&amp;gt;. В дальнейшем, так как &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;g = \frac{\log n}{2 \log e}&amp;lt;/tex&amp;gt;, м.ч. должны влезать в контейнер. Каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log\log n \log n&amp;lt;/tex&amp;gt; блоков, каждое м.ч. может содержать &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{k \log n}{g}) = O(k \log e)&amp;lt;/tex&amp;gt; блоков. Заметим, что используется неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; для [[#lemma5|лемме №5]] Поэтому предполагается, что &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2 \log e}&amp;lt;/tex&amp;gt; м.ч., в каждом из которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков битов числа, упакованны в один контейнер. Для каждого м.ч. используется маркер из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log e&amp;lt;/tex&amp;gt; бит, который показывает, к какому набору он принадлежит. Предполагаем, что маркеры так же упакованы в контейнеры, как и м.ч. Так как каждый контейнер для маркеров содержит &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2 \log e}&amp;lt;/tex&amp;gt; маркеров, то для каждого контейнера требуется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит. Таким образом, [[#lemma5|лемма №5]] может быть применена для помещения м.ч. в наборы, которым они принадлежат. Так как используется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log e}{ \log n})&amp;lt;/tex&amp;gt; контейнеров, то время, необходимое для помещения м.ч. в их наборы, равно &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log e}{ \log n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит отметить, что процесс помещения нестабилен, т.к. основан на алгоритме из [[#lemma5|леммы №5]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При таком помещении сразу возникает следующая проблема.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим число &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;, которое является &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ым в наборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;. Рассмотрим блок &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; (назовем его &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'&amp;lt;/tex&amp;gt;), который является &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ым м.ч. в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;. Когда используется вышеописанный метод перемещения нескольких следующих блоков &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; (назовем это &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a''&amp;lt;/tex&amp;gt;) в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a''&amp;lt;/tex&amp;gt; просто перемещен на позицию в наборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;, но не обязательно на позицию &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt; (где расположен &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'&amp;lt;/tex&amp;gt;). Если значение блока &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'&amp;lt;/tex&amp;gt; одинаково для всех чисел в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;, то это не создаст проблемы потому, что блок одинаков вне зависимости от того в какое место в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; помещен &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a''&amp;lt;/tex&amp;gt;. Иначе у нас возникает проблема дальнейшей сортировки. Поэтому поступаем следующим образом: На каждой стадии числа в одном наборе работают на общем блоке, который назовем &amp;quot;текущий блок набора&amp;quot;. Блоки, которые предшествуют текущему блоку содержат важные биты и идентичны для всех чисел в наборе. Когда помещаем больше бит в набор, последующие блоки помещаются в набор вместе с текущим блоком. Так вот, в вышеописанном процессе помещения предполагается, что самый значимый блок среди &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков {{---}} это текущий блок. Таким образом, после того, как эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков помещены в набор, изначальный текущий блок удаляется, потому что известно, что эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков перемещены в правильный набор, и нам не важно где находился начальный текущий блок. Тот текущий блок находится в перемещенных &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоках.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Стоит отметить, что после нескольких уровней деления размер наборов станет маленьким. Леммы [[#lemma3|3]], [[#lemma4|4]], [[#lemma5|5]] расчитаны на не очень маленькие наборы. Но поскольку сортируется набор из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; элементов в наборы размера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;, то проблем быть не должно.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Алгоритм сортировки===&lt;br /&gt;
&lt;br /&gt;
Algorithm &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;level&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{0}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{t}&amp;lt;/tex&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;advantage&amp;lt;/tex&amp;gt; {{---}} это неконсервативное преимущество равное &amp;lt;tex&amp;gt;k\log\log n&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{i}&amp;lt;/tex&amp;gt;-ые это входящие целые числа в наборе, которые надо отсортировать, &amp;lt;tex&amp;gt;level&amp;lt;/tex&amp;gt; это уровень рекурсии.&lt;br /&gt;
&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;level&amp;lt;/tex&amp;gt; равен &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; тогда изучаем размер набора. Если размер меньше или равен &amp;lt;tex&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;return&amp;lt;/tex&amp;gt;. Иначе делим этот набор в &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; 3 набора, используя [[#lemma2|лемму №2]], чтобы найти медиану, а затем используем [[#lemma5|лемму №5]] для сортировки. Для набора, где все элементы равны медиане, не рассматриваем текущий блок и текущим блоком делаем следующий. Создаем маркер, являющийся номером набора для каждого из чисел (0, 1 или 2). Затем направляем маркер для каждого числа назад к месту, где число находилось в начале. Также направляем двубитное число для каждого входного числа, указывающее на текущий блок.&lt;br /&gt;
# От &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;u = 1&amp;lt;/tex&amp;gt; до &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k&amp;lt;/tex&amp;gt;&lt;br /&gt;
## Упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{i}&amp;lt;/tex&amp;gt;-ый в часть из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1/k&amp;lt;/tex&amp;gt;-ых номеров контейнеров. Где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{i}&amp;lt;/tex&amp;gt; содержит несколько непрерывных блоков, которые состоят из &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{1}{k}&amp;lt;/tex&amp;gt;-ых битов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;. При этом у &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{i}&amp;lt;/tex&amp;gt; текущий блок это самый крупный блок.&lt;br /&gt;
## Вызываем &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;level - 1&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{0}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{t}&amp;lt;/tex&amp;gt;). Когда алгоритм возвращается из этой рекурсии, маркер, показывающий для каждого числа, к какому набору это число относится, уже направлен назад к месту, где число находится во входных данных. Число, имеющее наибольшее число бит в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;, показывающее на текущий блок в нем, так же направлено назад к &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
## Отправляем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;-ые к их наборам, используя [[#lemma5|лемму №5]].&lt;br /&gt;
&lt;br /&gt;
Algorithm IterateSort&lt;br /&gt;
Call &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log_{k}((\log n)/4)&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{0}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{n - 1}&amp;lt;/tex&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
от 1 до 5&lt;br /&gt;
# Помещаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; в соответствующий набор с помощью блочной сортировки (англ. ''bucket sort''), потому что наборов около &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Для каждого набора &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S = &amp;lt;/tex&amp;gt;{&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i_{0}}, a_{i_{1}}, \ldots, a_{i_{t}}&amp;lt;/tex&amp;gt;}, если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t &amp;gt; \sqrt{n}&amp;lt;/tex&amp;gt;, вызываем &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log_{k}(\frac{\log n}{4})&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i_{0}}, a_{i_{1}}, \ldots, a_{i_{t}}&amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Время работы алгоритма &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log\log n}{\log k})&amp;lt;/tex&amp;gt;, что доказывает лемму.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Уменьшение числа бит в числах==&lt;br /&gt;
Один из способов ускорить сортировку {{---}} уменьшить число бит в числе. Один из способов уменьшить число бит в числе {{---}} использовать деление пополам (эту идею впервые подал van Emde Boas). Деление пополам заключается в том, что количество оставшихся бит в числе уменьшается в 2 раза. Это быстрый способ, требующий &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(m)&amp;lt;/tex&amp;gt; памяти. Для своего дерева Андерссон использует хеширование, что позволяет сократить количество памяти до &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Для того чтобы еще ускорить алгоритм, необходимо упаковать несколько чисел в один контейнер, чтобы затем за константное количество шагов произвести хеширование для всех чисел, хранимых в контейнере. Для этого используется хеш-функция для хеширования &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в таблицу размера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; за константное время без коллизий. Для этого используется модифицированная хеш-функция авторства: Dierzfelbinger и Raman.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм: Пусть целое число &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b \geqslant 0&amp;lt;/tex&amp;gt; и пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U = \{0, \ldots, 2^b - 1\}&amp;lt;/tex&amp;gt;. Класс &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;H_{b,s}&amp;lt;/tex&amp;gt; хеш-функций из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, \ldots, 2^s - 1\}&amp;lt;/tex&amp;gt; определен как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;H_{b,s} = \{h_{a} \mid 0 &amp;lt; a &amp;lt; 2^b, a \equiv 1 (\bmod 2)\}&amp;lt;/tex&amp;gt; и для всех &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;x&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U&amp;lt;/tex&amp;gt;: &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}(x) = (ax&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\bmod&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^b)&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;div&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^{b - s}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм базируется на [[#lemma1|лемме №1]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Взяв &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s = 2 \log n&amp;lt;/tex&amp;gt;, получаем хеш-функцию &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}&amp;lt;/tex&amp;gt;, которая захеширует &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U&amp;lt;/tex&amp;gt; в таблицу размера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; без коллизий. Очевидно, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}(x)&amp;lt;/tex&amp;gt; может быть посчитана для любого &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;x&amp;lt;/tex&amp;gt; за константное время. Если упаковать несколько чисел в один контейнер так, что они разделены несколькими битами нулей, то можно применить &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}&amp;lt;/tex&amp;gt; ко всему контейнеру, и в результате все хеш-значения для всех чисел в контейнере будут посчитаны. Заметим, что это возможно только потому, что в вычисление хеш-значения вовлечены только (&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\bmod&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^b&amp;lt;/tex&amp;gt;) и (&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;div&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^{b - s}&amp;lt;/tex&amp;gt;). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Такая хеш-функция может быть найдена за &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следует отметить, что, несмотря на размер таблицы &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;, потребность в памяти не превышает &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt;, потому что хеширование используется только для уменьшения количества бит в числе.&lt;br /&gt;
&lt;br /&gt;
==Сортировка по ключу==&lt;br /&gt;
Предположим, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел должны быть отсортированы, и в каждом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит. Будем считать, что в каждом числе есть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h&amp;lt;/tex&amp;gt; сегментов, в каждом из которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{m}{h}&amp;lt;/tex&amp;gt; бит. Теперь применяем хеширование ко всем сегментам и получаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2h \log n&amp;lt;/tex&amp;gt; бит хешированных значений для каждого числа. После сортировки на хешированных значениях для всех начальных чисел начальная задача по сортировке &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит в каждом стала задачей по сортировке &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{m}{h}&amp;lt;/tex&amp;gt; бит в каждом.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Также рассмотрим проблему последующего разделения. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{2}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{p}&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; {{---}} множество чисeл. Необходимо разделить &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; наборов, таких, что: &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; a_{1} &amp;lt; S_{1} &amp;lt; a_{2} &amp;lt; \ldots &amp;lt; a_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;. Так как используется '''сортировка по ключу''' (англ. ''signature sorting'') то перед тем, как делать вышеописанное разделение, необходимо поделить биты в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h&amp;lt;/tex&amp;gt; сегментов и взять некоторые из них. Так же делим биты для каждого числа из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; и оставляем только один в каждом числе. По существу, для каждого &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; берутся все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h&amp;lt;/tex&amp;gt; сегментов. Если соответствующие сегменты &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{j}&amp;lt;/tex&amp;gt; совпадают, то нам понадобится только один. Сегмент, который берется для числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; это сегмент, который выделяется из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;. Таким образом, начальная задача о разделении &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит преобразуется в несколько задач на разделение с числами по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{h}&amp;lt;/tex&amp;gt; бит.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Пример''':&lt;br /&gt;
[[Файл:Han-example.png|500px|thumb]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1} = 3, a_{2} = 5, a_{3} = 7, a_{4} = 10, S = \{1, 4, 6, 8, 9, 13, 14\}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Делим числа на два сегмента. Для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt; получим верхний сегмент &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{2}&amp;lt;/tex&amp;gt; {{---}} верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{3}&amp;lt;/tex&amp;gt; {{---}} верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{4}&amp;lt;/tex&amp;gt; {{---}} верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2&amp;lt;/tex&amp;gt;. Для элементов из S получим: для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;, так как он выделяется из нижнего сегмента &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;4&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;8&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;9&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;13&amp;lt;/tex&amp;gt; верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;14&amp;lt;/tex&amp;gt; верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;. Теперь все верхние сегменты, нижние сегменты &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;, нижние сегменты &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;4, 5, 6, 7,&amp;lt;/tex&amp;gt; нижние сегменты  &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;8, 9, 10&amp;lt;/tex&amp;gt; формируют &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;4&amp;lt;/tex&amp;gt; новые задачи на разделение.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Использование '''сортировки по ключу''' в данном алгоритме:&lt;br /&gt;
&lt;br /&gt;
Есть набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел, которые отсортированы как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}, a_{2}, \ldots, a_{p}&amp;lt;/tex&amp;gt;. Используем числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; для разделения набора &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{1}, b_{2}, \ldots, b_{q}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0}, S_{1}, \ldots, S_{p}&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;h = \frac{\log n}{c \log p}&amp;lt;/tex&amp;gt; для константы &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;c &amp;gt; 1&amp;lt;/tex&amp;gt;. (&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n \log p}&amp;lt;/tex&amp;gt;)-битные числа могут храниться в одном контейнере, содержащим &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит. Сначала рассматриваем биты в каждом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; и каждом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{i}&amp;lt;/tex&amp;gt; как сегменты одинаковой длины &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h} {\log\log n}&amp;lt;/tex&amp;gt;. Рассматриваем сегменты как числа. Чтобы получить неконсервативное преимущество для сортировки, числа в этих контейнерах (&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;-ом и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{i}&amp;lt;/tex&amp;gt;-ом) хешируются, и получается &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n}&amp;lt;/tex&amp;gt; хешированных значений в одном контейнере. При вычислении хеш-значений сегменты не влияют друг на друга, можно даже отделить четные и нечетные сегменты в два контейнера. Не умаляя общности считаем, что хеш-значения считаются за константное время. Затем, посчитав значения, два контейнера объединяем в один. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'_{i}&amp;lt;/tex&amp;gt; {{---}} хеш-контейнер для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;, аналогично &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b'_{i}&amp;lt;/tex&amp;gt;. В сумме хеш-значения имеют &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит, хотя эти значения разделены на сегменты по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{ \log\log n}&amp;lt;/tex&amp;gt; бит в каждом контейнере. Между сегментами получаются пустоты, которые забиваются нулями. Сначала упаковываются все сегменты в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит. Потом рассматривается каждый хеш-контейнер как число, и эти хеш-контейнеры сортируются за линейное время (сортировка будет рассмотрена чуть позже). После этой сортировки биты в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{i}&amp;lt;/tex&amp;gt; разрезаны на &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log\log n}{h}&amp;lt;/tex&amp;gt; сегментов. Таким образом, получилось дополнительное мультипликативное преимущество (англ. ''additional multiplicative advantage'') в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h} {\log\log n}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того, как вышеописанный процесс повторится &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; раз, получится неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{h} {\log\log n})^g&amp;lt;/tex&amp;gt; раз, в то время как потрачено только &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(gqt)&amp;lt;/tex&amp;gt; времени, так как каждое многократное деление происходит за линейное время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(qt)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Хеш-функция, которая используется, находится следующим образом. Будут хешироватся сегменты, &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log\log n}{h}&amp;lt;/tex&amp;gt;-ые, &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{\log\log n}{h})^2&amp;lt;/tex&amp;gt;-ые, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt; по счету в числе. Хеш-функцию для &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{\log\log n}{h})^t&amp;lt;/tex&amp;gt;-ых по счету сегментов, получаем нарезанием всех &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел на &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{\log\log n}{h})^t&amp;lt;/tex&amp;gt; сегментов. Рассматривая каждый сегмент как число, получаем &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;p(\frac{\log\log n}{h})^t&amp;lt;/tex&amp;gt; чисел. Затем получаем одну хеш-функцию для этих чисел. Так как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t &amp;lt; \log n&amp;lt;/tex&amp;gt;, то получится не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; хеш-функций.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим сортировку за линейное время, о которой было упомянуто ранее. Предполагается, что хешированные значения для каждого контейнера упакованы в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит. Есть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt; наборов, в каждом из которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q + p&amp;lt;/tex&amp;gt; хешированных контейнеров по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит в каждом. Эти контейнеры должны быть отсортированы в каждом наборе. Комбинируя все хеш-контейнеры в один pool, сортируем следующим образом.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Операция '''сортировки за линейное время''' (англ. ''Linear-Time-Sort'')&lt;br /&gt;
&lt;br /&gt;
Входные данные: &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;r \geqslant n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}.value&amp;lt;/tex&amp;gt; — значение числа &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt;, в котором &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}.set&amp;lt;/tex&amp;gt; — набор, в котором находится &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt;. Следует отметить, что всего есть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt; наборов.&lt;br /&gt;
&lt;br /&gt;
# Сортируем все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt; по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}.value&amp;lt;/tex&amp;gt;, используя bucket sort. Пусть все отсортированные числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;A[1..r]&amp;lt;/tex&amp;gt;. Этот шаг занимает линейное время, так как сортируется не менее &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел.&lt;br /&gt;
# Помещаем все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;A[j]&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;A[j].set&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Сортировка с использованием O(n log log n) времени и памяти==&lt;br /&gt;
Для сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел в диапазоне &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt; предполагается, что в нашем консервативном алгоритме используется контейнер длины &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log (m + n))&amp;lt;/tex&amp;gt;. Далее везде считается, что все числа упакованы в контейнеры одинаковой длины. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Берем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1/e = 5&amp;lt;/tex&amp;gt; для ЭП-дерева Андерссона. Следовательно, у корня будет &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{1}{5}}&amp;lt;/tex&amp;gt; детей, и каждое ЭП-дерево в каждом ребенке будет иметь &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{4}{5}}&amp;lt;/tex&amp;gt; листьев. В отличие от оригинального дерева, за раз вставляется не один элемент, а &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d^2&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d&amp;lt;/tex&amp;gt; — количество детей узла дерева, в котором числа должны спуститься вниз. Алгоритм полностью опускает все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d^2&amp;lt;/tex&amp;gt; чисел на один уровень. В корне опускаются &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел на следующий уровень. После того, как все числа опустились на следующий уровень, они успешно разделились на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{1} = n^{1/5}&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}, S_{2}, \ldots, S_{t_{1}}&amp;lt;/tex&amp;gt;, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{4}{5}}&amp;lt;/tex&amp;gt; чисел и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i} &amp;lt; S_{j}, i &amp;lt; j&amp;lt;/tex&amp;gt;. Затем, берутся &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{8}{25}}&amp;lt;/tex&amp;gt; чисел из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и опускаются на следующий уровень ЭП-дерева. Это повторяется, пока все числа не опустятся на следующий уровень. На этом шаге числа разделены на &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;t_{2} = n^{\frac{1}{5}}n^{\frac{4}{25}} = n^{\frac{9}{25}}&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T_{1}, T_{2}, \ldots, T_{t_{2}}&amp;lt;/tex&amp;gt;, аналогичных наборам &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt;, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{16}{25}}&amp;lt;/tex&amp;gt; чисел. Теперь числа опускаются дальше в ЭП-дереве.&lt;br /&gt;
&lt;br /&gt;
Нетрудно заметить, что перебалансирока занимает &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; времени с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени на уровень, аналогично стандартному ЭП-дереву Андерссона.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нам следует нумеровать уровни ЭП-дерева с корня, начиная с нуля. Рассмотрим спуск вниз на уровне &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;. Имеется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;t = n^{1 - (\frac{4}{5})^S}&amp;lt;/tex&amp;gt; наборов по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{(\frac{4}{5})^S}&amp;lt;/tex&amp;gt; чисел в каждом. Так как каждый узел на данном уровне имеет &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;p = n^{\frac{1}{5} \cdot (\frac{4}{5})^S}&amp;lt;/tex&amp;gt; детей, то на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s + 1&amp;lt;/tex&amp;gt; уровень опускаются &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;q = n^{\frac{2}{5} \cdot (\frac{4}{5})^S}&amp;lt;/tex&amp;gt; чисел для каждого набора, или всего &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;qt \geqslant n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел для всех наборов за один раз.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Спуск вниз можно рассматривать как сортировку &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел в каждом наборе вместе с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; числами &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}, a_{2}, \ldots, a_{p}&amp;lt;/tex&amp;gt; из ЭП-дерева, так, что эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел разделены в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0}, S_{1}, \ldots, S_{p}&amp;lt;/tex&amp;gt; таких, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; a_{1} &amp;lt; \ldots &amp;lt; a_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел не надо полностью сортировать и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q = p^2&amp;lt;/tex&amp;gt;, то можно использовать [[#lemma6|лемму №6]] для сортировки. Для этого необходимо неконсервативное преимущество, которое получается с помощью [[Сортировка Хана#Signature sorting|signature sorting]]. Для этого используется линейная техника многократного деления (англ. ''multi-dividing technique'').&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; сокращений бит в  [[Сортировка Хана#Signature sorting|signature sorting]] получаем неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{h}{ \log\log n})^g&amp;lt;/tex&amp;gt;. Мы не волнуемся об этих сокращениях до конца потому, что после получения неконсервативного преимущества мы можем переключиться на [[#lemma6|лемму №6]] для завершения разделения &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел с помощью &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел на наборы. Заметим, что по природе битового сокращения начальная задача разделения для каждого набора перешла в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w&amp;lt;/tex&amp;gt; подзадач разделения на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w&amp;lt;/tex&amp;gt; поднаборов для какого-то числа &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Теперь для каждого набора все его поднаборы в подзадачах собираются в один набор. Затем, используя [[#lemma6|лемму №6]], делается разделение. Так как получено неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{h}{\log\log n})^g&amp;lt;/tex&amp;gt; и работа происходит на уровнях не ниже, чем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log\log\log n&amp;lt;/tex&amp;gt;, то алгоритм занимает &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{qt \log\log n}{g(\log h - \log\log\log n) - \log\log\log n}) = O(\log\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В итоге разделились &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; числами в каждый набор. То есть получилось, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; e_{1} &amp;lt; S_{1} &amp;lt; \ldots &amp;lt; e_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;e_{i}&amp;lt;/tex&amp;gt; {{---}} сегмент &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;, полученный с помощью битового сокращения. Такое разделение получилось комбинированием всех поднаборов в подзадачах. Предполагаем, что числа хранятся в массиве &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B&amp;lt;/tex&amp;gt; так, что числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt; предшествуют числам в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{j}&amp;lt;/tex&amp;gt; если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i &amp;lt; j&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;e_{i}&amp;lt;/tex&amp;gt; хранится после &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i - 1}&amp;lt;/tex&amp;gt;, но до &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[i]&amp;lt;/tex&amp;gt; находится в поднаборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[i].subset&amp;lt;/tex&amp;gt;. Чтобы позволить разделению выполниться, для каждого поднабора помещаем все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[j]&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[j].subset&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На это потребуется линейное время и место.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим проблему упаковки, которая решается следующим образом. Считается, что число бит в контейнере &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \geqslant \log\log\log n&amp;lt;/tex&amp;gt;, потому что в противном случае можно использовать radix sort для сортировки чисел. У контейнера есть &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n}&amp;lt;/tex&amp;gt; хешированных значений (сегментов) в себе на уровне &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log h&amp;lt;/tex&amp;gt; в ЭП-дереве. Полное число хешированных бит в контейнере равно &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;(2 \log n)(c \log\log n)&amp;lt;/tex&amp;gt; бит. Хешированные биты в контейнере выглядят как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0^{i}t_{1}0^{i}t_{2} \ldots t&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{\frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{k}&amp;lt;/tex&amp;gt;-ые — хешированные биты, а нули {{---}} это просто нули. Сначала упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров в один и получаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{1} = 0^{j}t_{1, 1}t_{2, 1} \ldots t_{\log\log n, 1}0^{j}t_{1, 2} \ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{  \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{i, k}&amp;lt;/tex&amp;gt;: элемент с номером &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k = 1, 2,  \ldots, &amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n}&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ого контейнера. Используем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; шагов, чтобы упаковать &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{1}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{2} = 0&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;^{\frac{jh}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{1, 1}t_{2, 1} \ldots t_{\log\log n, 1}t_{1, 2}t_{2, 2} \ldots t_{1,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{2,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;. Теперь упакованные хеш-биты занимают &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{c}&amp;lt;/tex&amp;gt; бит. Используем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; времени чтобы распаковать &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{2}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{3, k} = 0&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;^{\frac{jh}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0^{r}t_{k, 1}0^{r}t_{k, 2} \ldots t_{k,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k = 1, 2, \ldots, \log\log n&amp;lt;/tex&amp;gt;. Затем, используя &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; времени, упаковываем эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров в один &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{4} = 0^{r}t_{1, 1}0^{r}t_{1, 2} \ldots t_{1,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0^{r}t_{2, 1} \ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;. Затем, используя &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; шагов, упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{4}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{5} = 0^{s}t_{1, 1}t_{1, 2} \ldots t_{1,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{2, 1}t_{2, 2} \ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;. В итоге используется &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; времени для упаковки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров. Считаем, что время, потраченное на один контейнер — константа.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка подсчетом]]&lt;br /&gt;
* [[Цифровая сортировка]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [http://www.sciencedirect.com/science/article/pii/S019667740300155X Deterministic Sorting in O(n log log n) Time and Linear Space. Yijie Han.]&lt;br /&gt;
* А. Андерссон. Fast deterministic sorting and searching in linear space. Proc. 1996 IEEE Symp. on Foundations of Computer Science. 135-141(1996)&lt;br /&gt;
* [http://dl.acm.org/citation.cfm?id=1236460 A. Andersson, M. Thorup. Dynamic ordered sets with exponential search trees.]&lt;br /&gt;
* [[wikipedia:en:Integer_sorting|Wikipedia {{---}} Integer sorting]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Сортировка]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%A5%D0%B0%D0%BD%D0%B0&amp;diff=48001</id>
		<title>Сортировка Хана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%A5%D0%B0%D0%BD%D0%B0&amp;diff=48001"/>
				<updated>2015-06-07T17:27:49Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка Хана''' (англ. ''Hansort'') {{---}} сложный алгоритм сортировки целых чисел со сложностью &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов для сортировки.&lt;br /&gt;
&lt;br /&gt;
Данная статья писалась на основе брошюры Хана (англ. ''Yijie Han''), посвященной этой сортировке.&lt;br /&gt;
&lt;br /&gt;
== Описание ==&lt;br /&gt;
Алгоритм построен на основе '''экспоненциального поискового дерева Андерсона''' (англ. ''Andersson's exponential search tree''). Сортировка происходит за счет вставки целых чисел в экспоненциальное поисковое дерево (''далее {{---}} ЭП-дерево'').&lt;br /&gt;
&lt;br /&gt;
== Экспоненциальное поисковое дерево Андерсона ==&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = '''ЭП-дерево''' {{---}} это дерево поиска, в котором все ключи хранятся в листьях этого дерева и количество детей у каждого узла уменьшается экспоненциально от глубины узла.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Файл:Exp-tree.png|400px|thumb|right|Общая структура ЭП-дерева]]&lt;br /&gt;
&lt;br /&gt;
Структура ЭП-дерева:&lt;br /&gt;
&lt;br /&gt;
1) Корень имеет &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\Theta (n^e)&amp;lt;/tex&amp;gt; сыновей &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;( 0 &amp;lt; e &amp;lt; 1 )&amp;lt;/tex&amp;gt;. Все сыновья являются ЭП-деревьями.&lt;br /&gt;
&lt;br /&gt;
2) Каждое поддерево корня имеет &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\Theta(n^{1-e})&amp;lt;/tex&amp;gt; сыновей.&lt;br /&gt;
&lt;br /&gt;
В этом дереве &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; уровней. При нарушении баланса дерева необходимо балансирование, которое требует &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; времени при &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; вставленных целых числах. Такое время достигается за счет вставки чисел группами, а не поодиночке, как изначально предлагал Андерссон.&lt;br /&gt;
&lt;br /&gt;
==Определения== &lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 '''Контейнер''' {{---}} объект, в которым хранятся наши данные. Например: 32-битные и 64-битные числа, массивы, вектора.}}&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Алгоритм, сортирующий &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел из множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt;, называется '''консервативным''', если длина контейнера (число бит в контейнере) равна &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log(m + n))&amp;lt;/tex&amp;gt;. Если длина больше, то алгоритм '''неконсервативный'''.&lt;br /&gt;
 }}&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Если сортируются целые числа из множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt; с длиной контейнера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log (m + n)&amp;lt;/tex&amp;gt; с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \geqslant 1&amp;lt;/tex&amp;gt;, тогда сортировка происходит с '''неконсервативным преимуществом''' &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Для множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; определим&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\min(S) = \min\limits_{a \in S} a&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\max(S) = \max\limits_{a \in S} a&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S1 &amp;lt; S2&amp;lt;/tex&amp;gt; если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\max(S1) \leqslant \min(S2)&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Предположим, есть набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел, которые уже отсортированы как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}, a_{2}, \ldots, a_{p}&amp;lt;/tex&amp;gt; и набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{1}, b_{2}, \ldots, b_{q}&amp;lt;/tex&amp;gt;. Тогда '''разделением''' &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; числами называется &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0}, S_{1}, \ldots, S_{p}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; a_{1} &amp;lt; S_{1} &amp;lt; \ldots &amp;lt; a_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Леммы==&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma1&lt;br /&gt;
|about = № 1&lt;br /&gt;
|statement = &lt;br /&gt;
Даны целые числа &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b \geqslant s \geqslant 0&amp;lt;/tex&amp;gt;, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; является подмножеством множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, \ldots, 2^b - 1\}&amp;lt;/tex&amp;gt;, содержащим &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; элементов, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t \geqslant 2^{-s + 1}С^k_{n}&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}&amp;lt;/tex&amp;gt;, принадлежащая &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;H_{b,s}&amp;lt;/tex&amp;gt;, может быть выбрана за время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(bn^2)&amp;lt;/tex&amp;gt; так, что количество коллизий &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;coll(h_{a}, T) \leqslant t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma2&lt;br /&gt;
|about = № 2&lt;br /&gt;
|statement = &lt;br /&gt;
Выбор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;-ого наибольшего числа среди &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел, упакованных в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнеров, может быть сделан за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log g}{g})&amp;lt;/tex&amp;gt; и с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти. В том числе, так  может быть найдена медиана.&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Так как возможно делать попарное сравнение &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел в одном контейнере с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; числами в другом и извлекать большие числа из одного контейнера и меньшие из другого за константное время, возможно упаковать медианы из первого, второго, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;-ого чисел из 5 контейнеров в один контейнер за константное время. Таким образом, набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; из медиан теперь содержится в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{5g}&amp;lt;/tex&amp;gt; контейнерах. Рекурсивно находим медиану &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;m&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;. Используя &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;m&amp;lt;/tex&amp;gt;, уберем хотя бы &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{4}&amp;lt;/tex&amp;gt; чисел среди &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt;. Затем упакуем оставшиеся из &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнеров в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{3n}{4g}&amp;lt;/tex&amp;gt; контейнеров и затем продолжим рекурсию.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma3&lt;br /&gt;
|about = № 3&lt;br /&gt;
|statement = &lt;br /&gt;
Если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; целых чисел, в сумме использующих &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит, упакованы в один контейнер, тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнерах могут быть отсортированы за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log g}{g})&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Так как используется только &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит в каждом контейнере для хранения &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел, используем bucket sort, чтобы отсортировать все контейнеры, представляя каждый как число, что занимает &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; времени и памяти. Так как используется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит на контейнер, понадобится &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; шаблонов для всех контейнеров. Затем поместим &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;g &amp;lt; \frac{\log n}{2}&amp;lt;/tex&amp;gt; контейнеров с одинаковым шаблоном в одну группу. Для каждого шаблона останется не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g - 1&amp;lt;/tex&amp;gt; контейнеров, которые не смогут образовать группу. Поэтому не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}(g - 1)&amp;lt;/tex&amp;gt; контейнеров не смогут сформировать группу. Для каждой группы помещаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-е число во всех &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнерах в один. Таким образом берутся &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;-целых векторов и получаются &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;-целых векторов, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ый вектор содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ое число из входящего вектора. Эта транспозиция может быть сделана за время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(g \log g)&amp;lt;/tex&amp;gt;, с использованием &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(g)&amp;lt;/tex&amp;gt; памяти. Для всех групп это занимает время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log g}{g})&amp;lt;/tex&amp;gt;, с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
Для контейнеров вне групп (которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}(g - 1)&amp;lt;/tex&amp;gt; штук) разбираем и собираем заново контейнеры. На это потребуется не более &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; времени и памяти. После всего этого используем карманную сортировку вновь для сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; контейнеров. Таким образом, все числа отсортированы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заметим, что когда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g = O( \log n)&amp;lt;/tex&amp;gt;, сортировка &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнеров произойдет за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O((\frac{n}{g})&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n)&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти. Выгода очевидна.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma4&lt;br /&gt;
|about = № 4&lt;br /&gt;
|statement = &lt;br /&gt;
Примем, что каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt; \log m &amp;gt; \log n&amp;lt;/tex&amp;gt; бит, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{g}&amp;lt;/tex&amp;gt; бит, упакованы в один контейнер. Если каждое число имеет маркер, содержащий &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2g}&amp;lt;/tex&amp;gt; бит, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; маркеров упакованы в один контейнер таким же образом&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;^*&amp;lt;/tex&amp;gt;, что и числа, тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнерах могут быть отсортированы по их маркерам за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log\log n}{g})&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
(*): если число &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; упаковано как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;-ое число в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt;-ом контейнере для чисел, тогда маркер для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; упакован как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;-ый маркер в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt;-ом контейнере для маркеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Контейнеры для маркеров могут быть отсортированы с помощью bucket sort потому, что каждый контейнер использует &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит. Сортировка сгруппирует контейнеры для чисел как в [[#lemma3|лемме №3]]. Перемещаем каждую группу контейнеров для чисел.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma5&lt;br /&gt;
|about = № 5&lt;br /&gt;
|statement =&lt;br /&gt;
Предположим, что каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \log\log n &amp;gt; \log n&amp;lt;/tex&amp;gt; бит, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{g}&amp;lt;/tex&amp;gt; бит, упакованы в один контейнер, что каждое число имеет маркер, содержащий &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2g}&amp;lt;/tex&amp;gt; бит, и что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; маркеров упакованы в один контейнер тем же образом что и числа. Тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнерах могут быть отсортированы по своим маркерам за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Заметим, что несмотря на то, что длина контейнера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \log\log n&amp;lt;/tex&amp;gt; бит, всего &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит используется для хранения упакованных чисел. Так же как в [[#lemma3|лемме №3]] и [[#lemma4|лемме №4]] сортируем контейнеры упакованных маркеров с помощью bucket sort. Для того, чтобы перемещать контейнеры чисел, помещаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; вместо &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнеров чисел в одну группу. Для транспозиции чисел в группе, содержащей &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; контейнеров, упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; контейнеров в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;, упаковывая &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров в один. Далее делаем транспозицию над &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнерами. Таким образом перемещение занимает всего &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(g \log\log n)&amp;lt;/tex&amp;gt; времени для каждой группы и &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; времени для всех чисел. После завершения транспозиции, распаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнеров в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; контейнеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заметим, что если длина контейнера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \log\log n&amp;lt;/tex&amp;gt; и только &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит используется для упаковки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \leqslant \log n&amp;lt;/tex&amp;gt; чисел в один контейнер, тогда выбор в [[#lemma2|лемме №2]] может быть сделан за время и память &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt;, потому что упаковка в доказательстве [[#lemma2|лемме №2]] теперь может быть сделана за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma6&lt;br /&gt;
|about = № 6&lt;br /&gt;
|statement = &lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел можно отсортировать в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{\sqrt{n}}&amp;lt;/tex&amp;gt; таким образом, что в каждом наборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; чисел и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i} &amp;lt; S_{j}&amp;lt;/tex&amp;gt; при &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i &amp;lt; j&amp;lt;/tex&amp;gt;, за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log\log n} {\log k})&amp;lt;/tex&amp;gt; и место &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; с неконсервативным преимуществом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log\log n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Алгоритм сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; наборов, представленный ниже, является доказательством данной леммы. &lt;br /&gt;
&lt;br /&gt;
Постановка задачи и решение некоторых проблем:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим проблему сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел из множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; наборов, как в условии леммы. Предполагаем, что каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log\log n \log m&amp;lt;/tex&amp;gt; бит и хранит число в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит. Поэтому неконсервативное преимущество {{---}} &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log \log n&amp;lt;/tex&amp;gt;. Также предполагаем, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \geqslant \log n \log\log n&amp;lt;/tex&amp;gt;. Иначе можно использовать radix sort для сортировки за время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; и линейную память. Делим &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит, используемых для представления каждого числа, в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; блоков. Таким образом, каждый блок содержит как минимум &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; бит. &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ый блок содержит с &lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{i \log m} {\log n}&amp;lt;/tex&amp;gt;-ого по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{(i + 1) \log m} {\log n - 1})&amp;lt;/tex&amp;gt;-ый биты. Биты считаются с наименьшего бита, начиная с нуля. Теперь у нас имеется &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log n&amp;lt;/tex&amp;gt;-уровневый алгоритм, который работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На каждой стадии работаем с одним блоком бит. Назовем эти блоки маленькими числами (далее м.ч.), потому что каждое м.ч. теперь содержит только &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{\log n}&amp;lt;/tex&amp;gt; бит. Каждое число представлено и соотносится с м.ч., над которым работаем в данный момент. Положим, что нулевая стадия работает с самым большим блоком (блок номер &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n - 1&amp;lt;/tex&amp;gt;). Предполагаем, что биты этих м.ч. упакованы в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{\log n}&amp;lt;/tex&amp;gt; контейнеров с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; м.ч. упакованными в один контейнер. Пренебрегая временем, потраченным на эту упаковку, считаем, что она бесплатна. По [[#lemma2|лемме №2]] находим медиану этих &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; м.ч. за время и память &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{\log n})&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} это найденная медиана. Тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; м.ч. могут быть разделены на не более чем три группы: &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{3}&amp;lt;/tex&amp;gt;. &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt; содержит м.ч., которые меньше &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt; содержит м.ч., равные &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{3}&amp;lt;/tex&amp;gt; содержит м.ч., большие &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;. Также мощность &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{3} &amp;lt;/tex&amp;gt; не превосходит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n/2&amp;lt;/tex&amp;gt;. Мощность &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt; может быть любой. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S'_{2}&amp;lt;/tex&amp;gt; {{---}} это набор чисел, у которых наибольший блок находится в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt;. Тогда убираем из дальнейшего рассмотрения &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{\log n}&amp;lt;/tex&amp;gt; бит (наибольший блок) из каждого числа, принадлежащего &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S'_{2}&amp;lt;/tex&amp;gt;. Таким образом, после первой стадии каждое число находится в наборе размера не большего половины размера начального набора или один из блоков в числе убран из дальнейшего рассмотрения. Так как в каждом числе только &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; блоков, для каждого числа потребуется не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; стадий, чтобы поместить его в набор половинного размера. За &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log n&amp;lt;/tex&amp;gt; стадий все числа будут отсортированы. Так как на каждой стадии работаем с &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{\log n}&amp;lt;/tex&amp;gt; контейнерами, то игнорируя время, необходимое на упаковку м.ч. в контейнеры и помещение м.ч. в нужный набор, затрачивается &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени из-за &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log n&amp;lt;/tex&amp;gt; стадий.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложная часть алгоритма заключается в том, как поместить м.ч. в набор, которому принадлежит соответствующее число, после предыдущих операций деления набора в нашем алгоритме. Предположим, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел уже поделены в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;e&amp;lt;/tex&amp;gt; наборов. Используем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log e&amp;lt;/tex&amp;gt; битов чтобы сделать марки для каждого набора. Теперь используем [[#lemma5|лемме №5]]. Полный размер маркера для каждого контейнера должен быть &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt;, и маркер использует &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log e&amp;lt;/tex&amp;gt; бит, значит количество маркеров &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; в каждом контейнере должно быть не более &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2\log e}&amp;lt;/tex&amp;gt;. В дальнейшем, так как &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;g = \frac{\log n}{2 \log e}&amp;lt;/tex&amp;gt;, м.ч. должны влезать в контейнер. Каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log\log n \log n&amp;lt;/tex&amp;gt; блоков, каждое м.ч. может содержать &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{k \log n}{g}) = O(k \log e)&amp;lt;/tex&amp;gt; блоков. Заметим, что используется неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; для [[#lemma5|лемме №5]] Поэтому предполагается, что &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2 \log e}&amp;lt;/tex&amp;gt; м.ч., в каждом из которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков битов числа, упакованны в один контейнер. Для каждого м.ч. используется маркер из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log e&amp;lt;/tex&amp;gt; бит, который показывает, к какому набору он принадлежит. Предполагаем, что маркеры так же упакованы в контейнеры, как и м.ч. Так как каждый контейнер для маркеров содержит &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2 \log e}&amp;lt;/tex&amp;gt; маркеров, то для каждого контейнера требуется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит. Таким образом, [[#lemma5|лемма №5]] может быть применена для помещения м.ч. в наборы, которым они принадлежат. Так как используется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log e}{ \log n})&amp;lt;/tex&amp;gt; контейнеров, то время, необходимое для помещения м.ч. в их наборы, равно &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log e}{ \log n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит отметить, что процесс помещения нестабилен, т.к. основан на алгоритме из [[#lemma5|леммы №5]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При таком помещении сразу возникает следующая проблема.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим число &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;, которое является &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ым в наборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;. Рассмотрим блок &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; (назовем его &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'&amp;lt;/tex&amp;gt;), который является &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ым м.ч. в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;. Когда используется вышеописанный метод перемещения нескольких следующих блоков &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; (назовем это &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a''&amp;lt;/tex&amp;gt;) в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a''&amp;lt;/tex&amp;gt; просто перемещен на позицию в наборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;, но не обязательно на позицию &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt; (где расположен &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'&amp;lt;/tex&amp;gt;). Если значение блока &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'&amp;lt;/tex&amp;gt; одинаково для всех чисел в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;, то это не создаст проблемы потому, что блок одинаков вне зависимости от того в какое место в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; помещен &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a''&amp;lt;/tex&amp;gt;. Иначе у нас возникает проблема дальнейшей сортировки. Поэтому поступаем следующим образом: На каждой стадии числа в одном наборе работают на общем блоке, который назовем &amp;quot;текущий блок набора&amp;quot;. Блоки, которые предшествуют текущему блоку содержат важные биты и идентичны для всех чисел в наборе. Когда помещаем больше бит в набор, последующие блоки помещаются в набор вместе с текущим блоком. Так вот, в вышеописанном процессе помещения предполагается, что самый значимый блок среди &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков {{---}} это текущий блок. Таким образом, после того, как эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков помещены в набор, изначальный текущий блок удаляется, потому что известно, что эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков перемещены в правильный набор, и нам не важно где находился начальный текущий блок. Тот текущий блок находится в перемещенных &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоках.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Стоит отметить, что после нескольких уровней деления размер наборов станет маленьким. Леммы [[#lemma3|3]], [[#lemma4|4]], [[#lemma5|5]] расчитаны на не очень маленькие наборы. Но поскольку сортируется набор из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; элементов в наборы размера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;, то проблем быть не должно.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Алгоритм сортировки===&lt;br /&gt;
&lt;br /&gt;
Algorithm &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;level&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{0}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{t}&amp;lt;/tex&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;advantage&amp;lt;/tex&amp;gt; {{---}} это неконсервативное преимущество равное &amp;lt;tex&amp;gt;k\log\log n&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{i}&amp;lt;/tex&amp;gt;-ые это входящие целые числа в наборе, которые надо отсортировать, &amp;lt;tex&amp;gt;level&amp;lt;/tex&amp;gt; это уровень рекурсии.&lt;br /&gt;
&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;level&amp;lt;/tex&amp;gt; равен &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; тогда изучаем размер набора. Если размер меньше или равен &amp;lt;tex&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;return&amp;lt;/tex&amp;gt;. Иначе делим этот набор в &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; 3 набора, используя [[#lemma2|лемму №2]], чтобы найти медиану, а затем используем [[#lemma5|лемму №5]] для сортировки. Для набора, где все элементы равны медиане, не рассматриваем текущий блок и текущим блоком делаем следующий. Создаем маркер, являющийся номером набора для каждого из чисел (0, 1 или 2). Затем направляем маркер для каждого числа назад к месту, где число находилось в начале. Также направляем двубитное число для каждого входного числа, указывающее на текущий блок.&lt;br /&gt;
# От &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;u = 1&amp;lt;/tex&amp;gt; до &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k&amp;lt;/tex&amp;gt;&lt;br /&gt;
## Упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{i}&amp;lt;/tex&amp;gt;-ый в часть из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1/k&amp;lt;/tex&amp;gt;-ых номеров контейнеров. Где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{i}&amp;lt;/tex&amp;gt; содержит несколько непрерывных блоков, которые состоят из &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{1}{k}&amp;lt;/tex&amp;gt;-ых битов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;. При этом у &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{i}&amp;lt;/tex&amp;gt; текущий блок это самый крупный блок.&lt;br /&gt;
## Вызываем &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;level - 1&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{0}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{t}&amp;lt;/tex&amp;gt;). Когда алгоритм возвращается из этой рекурсии, маркер, показывающий для каждого числа, к какому набору это число относится, уже направлен назад к месту, где число находится во входных данных. Число, имеющее наибольшее число бит в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;, показывающее на текущий блок в нем, так же направлено назад к &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
## Отправляем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;-ые к их наборам, используя [[#lemma5|лемму №5]].&lt;br /&gt;
&lt;br /&gt;
Algorithm IterateSort&lt;br /&gt;
Call &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log_{k}((\log n)/4)&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{0}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{n - 1}&amp;lt;/tex&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
от 1 до 5&lt;br /&gt;
# Помещаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; в соответствующий набор с помощью блочной сортировки (англ. ''bucket sort''), потому что наборов около &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Для каждого набора &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S = &amp;lt;/tex&amp;gt;{&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i_{0}}, a_{i_{1}}, \ldots, a_{i_{t}}&amp;lt;/tex&amp;gt;}, если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t &amp;gt; \sqrt{n}&amp;lt;/tex&amp;gt;, вызываем &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log_{k}(\frac{\log n}{4})&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i_{0}}, a_{i_{1}}, \ldots, a_{i_{t}}&amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Время работы алгоритма &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log\log n}{\log k})&amp;lt;/tex&amp;gt;, что доказывает лемму.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Уменьшение числа бит в числах==&lt;br /&gt;
Один из способов ускорить сортировку {{---}} уменьшить число бит в числе. Один из способов уменьшить число бит в числе {{---}} использовать деление пополам (эту идею впервые подал van Emde Boas). Деление пополам заключается в том, что количество оставшихся бит в числе уменьшается в 2 раза. Это быстрый способ, требующий &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(m)&amp;lt;/tex&amp;gt; памяти. Для своего дерева Андерссон использует хеширование, что позволяет сократить количество памяти до &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Для того чтобы еще ускорить алгоритм, необходимо упаковать несколько чисел в один контейнер, чтобы затем за константное количество шагов произвести хеширование для всех чисел, хранимых в контейнере. Для этого используется хеш-функция для хеширования &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в таблицу размера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; за константное время без коллизий. Для этого используется модифицированная хеш-функция авторства: Dierzfelbinger и Raman.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм: Пусть целое число &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b \geqslant 0&amp;lt;/tex&amp;gt; и пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U = \{0, \ldots, 2^b - 1\}&amp;lt;/tex&amp;gt;. Класс &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;H_{b,s}&amp;lt;/tex&amp;gt; хеш-функций из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, \ldots, 2^s - 1\}&amp;lt;/tex&amp;gt; определен как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;H_{b,s} = \{h_{a} \mid 0 &amp;lt; a &amp;lt; 2^b, a \equiv 1 (\bmod 2)\}&amp;lt;/tex&amp;gt; и для всех &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;x&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U&amp;lt;/tex&amp;gt;: &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}(x) = (ax&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\bmod&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^b)&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;div&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^{b - s}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм базируется на [[#lemma1|лемме №1]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Взяв &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s = 2 \log n&amp;lt;/tex&amp;gt;, получаем хеш-функцию &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}&amp;lt;/tex&amp;gt;, которая захеширует &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U&amp;lt;/tex&amp;gt; в таблицу размера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; без коллизий. Очевидно, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}(x)&amp;lt;/tex&amp;gt; может быть посчитана для любого &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;x&amp;lt;/tex&amp;gt; за константное время. Если упаковать несколько чисел в один контейнер так, что они разделены несколькими битами нулей, то можно применить &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}&amp;lt;/tex&amp;gt; ко всему контейнеру, и в результате все хеш-значения для всех чисел в контейнере будут посчитаны. Заметим, что это возможно только потому, что в вычисление хеш-значения вовлечены только (&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\bmod&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^b&amp;lt;/tex&amp;gt;) и (&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;div&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^{b - s}&amp;lt;/tex&amp;gt;). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Такая хеш-функция может быть найдена за &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следует отметить, что, несмотря на размер таблицы &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;, потребность в памяти не превышает &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt;, потому что хеширование используется только для уменьшения количества бит в числе.&lt;br /&gt;
&lt;br /&gt;
==Сортировка по ключу==&lt;br /&gt;
Предположим, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел должны быть отсортированы, и в каждом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит. Будем считать, что в каждом числе есть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h&amp;lt;/tex&amp;gt; сегментов, в каждом из которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m/h&amp;lt;/tex&amp;gt; бит. Теперь применяем хеширование ко всем сегментам и получаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2h \log n&amp;lt;/tex&amp;gt; бит хешированных значений для каждого числа. После сортировки на хешированных значениях для всех начальных чисел начальная задача по сортировке &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит в каждом стала задачей по сортировке &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m/h&amp;lt;/tex&amp;gt; бит в каждом.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Также рассмотрим проблему последующего разделения. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{2}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{p}&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; {{---}} множество чисeл. Необходимо разделить &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; наборов, таких, что: &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; a_{1} &amp;lt; S_{1} &amp;lt; a_{2} &amp;lt; \ldots &amp;lt; a_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;. Так как используется '''сортировка по ключу''' (англ. ''signature sorting'') то перед тем, как делать вышеописанное разделение, необходимо поделить биты в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h&amp;lt;/tex&amp;gt; сегментов и взять некоторые из них. Так же делим биты для каждого числа из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; и оставляем только один в каждом числе. По существу, для каждого &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; берутся все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h&amp;lt;/tex&amp;gt; сегментов. Если соответствующие сегменты &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{j}&amp;lt;/tex&amp;gt; совпадают, то нам понадобится только один. Сегмент, который берется для числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; это сегмент, который выделяется из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;. Таким образом, начальная задача о разделении &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит преобразуется в несколько задач на разделение с числами по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{h}&amp;lt;/tex&amp;gt; бит.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Пример''':&lt;br /&gt;
[[Файл:Han-example.png|500px|thumb]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1} = 3, a_{2} = 5, a_{3} = 7, a_{4} = 10, S = \{1, 4, 6, 8, 9, 13, 14\}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Делим числа на два сегмента. Для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt; получим верхний сегмент &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{2}&amp;lt;/tex&amp;gt; {{---}} верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{3}&amp;lt;/tex&amp;gt; {{---}} верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{4}&amp;lt;/tex&amp;gt; {{---}} верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2&amp;lt;/tex&amp;gt;. Для элементов из S получим: для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;, так как он выделяется из нижнего сегмента &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;4&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;8&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;9&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;13&amp;lt;/tex&amp;gt; верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;14&amp;lt;/tex&amp;gt; верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;. Теперь все верхние сегменты, нижние сегменты &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;, нижние сегменты &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;4, 5, 6, 7,&amp;lt;/tex&amp;gt; нижние сегменты  &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;8, 9, 10&amp;lt;/tex&amp;gt; формируют &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;4&amp;lt;/tex&amp;gt; новые задачи на разделение.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Использование '''сортировки по ключу''' в данном алгоритме:&lt;br /&gt;
&lt;br /&gt;
Есть набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел, которые отсортированы как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}, a_{2}, \ldots, a_{p}&amp;lt;/tex&amp;gt;. Используем числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; для разделения набора &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{1}, b_{2}, \ldots, b_{q}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0}, S_{1}, \ldots, S_{p}&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;h = \frac{\log n}{c \log p}&amp;lt;/tex&amp;gt; для константы &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;c &amp;gt; 1&amp;lt;/tex&amp;gt;. (&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n \log p}&amp;lt;/tex&amp;gt;)-битные числа могут храниться в одном контейнере, содержащим &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит. Сначала рассматриваем биты в каждом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; и каждом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{i}&amp;lt;/tex&amp;gt; как сегменты одинаковой длины &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h} {\log\log n}&amp;lt;/tex&amp;gt;. Рассматриваем сегменты как числа. Чтобы получить неконсервативное преимущество для сортировки, числа в этих контейнерах (&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;-ом и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{i}&amp;lt;/tex&amp;gt;-ом) хешируются, и получается &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n}&amp;lt;/tex&amp;gt; хешированных значений в одном контейнере. При вычислении хеш-значений сегменты не влияют друг на друга, можно даже отделить четные и нечетные сегменты в два контейнера. Не умаляя общности считаем, что хеш-значения считаются за константное время. Затем, посчитав значения, два контейнера объединяем в один. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'_{i}&amp;lt;/tex&amp;gt; {{---}} хеш-контейнер для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;, аналогично &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b'_{i}&amp;lt;/tex&amp;gt;. В сумме хеш-значения имеют &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит, хотя эти значения разделены на сегменты по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{ \log\log n}&amp;lt;/tex&amp;gt; бит в каждом контейнере. Между сегментами получаются пустоты, которые забиваются нулями. Сначала упаковываются все сегменты в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит. Потом рассматривается каждый хеш-контейнер как число, и эти хеш-контейнеры сортируются за линейное время (сортировка будет рассмотрена чуть позже). После этой сортировки биты в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{i}&amp;lt;/tex&amp;gt; разрезаны на &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log\log n}{h}&amp;lt;/tex&amp;gt; сегментов. Таким образом, получилось дополнительное мультипликативное преимущество (англ. ''additional multiplicative advantage'') в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h} {\log\log n}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того, как вышеописанный процесс повторится &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; раз, получится неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{h} {\log\log n})^g&amp;lt;/tex&amp;gt; раз, в то время как потрачено только &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(gqt)&amp;lt;/tex&amp;gt; времени, так как каждое многократное деление происходит за линейное время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(qt)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Хеш-функция, которая используется, находится следующим образом. Будут хешироватся сегменты, &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log\log n}{h}&amp;lt;/tex&amp;gt;-ые, &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{\log\log n}{h})^2&amp;lt;/tex&amp;gt;-ые, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt; по счету в числе. Хеш-функцию для &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{\log\log n}{h})^t&amp;lt;/tex&amp;gt;-ых по счету сегментов, получаем нарезанием всех &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел на &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{\log\log n}{h})^t&amp;lt;/tex&amp;gt; сегментов. Рассматривая каждый сегмент как число, получаем &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;p(\frac{\log\log n}{h})^t&amp;lt;/tex&amp;gt; чисел. Затем получаем одну хеш-функцию для этих чисел. Так как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t &amp;lt; \log n&amp;lt;/tex&amp;gt;, то получится не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; хеш-функций.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим сортировку за линейное время, о которой было упомянуто ранее. Предполагается, что хешированные значения для каждого контейнера упакованы в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит. Есть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt; наборов, в каждом из которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q + p&amp;lt;/tex&amp;gt; хешированных контейнеров по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит в каждом. Эти контейнеры должны быть отсортированы в каждом наборе. Комбинируя все хеш-контейнеры в один pool, сортируем следующим образом.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Операция '''сортировки за линейное время''' (англ. ''Linear-Time-Sort'')&lt;br /&gt;
&lt;br /&gt;
Входные данные: &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;r &amp;gt; = n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}.value&amp;lt;/tex&amp;gt; — значение числа &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt;, в котором &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}.set&amp;lt;/tex&amp;gt; — набор, в котором находится &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt;. Следует отметить, что всего есть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt; наборов.&lt;br /&gt;
&lt;br /&gt;
# Сортируем все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt; по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}.value&amp;lt;/tex&amp;gt;, используя bucket sort. Пусть все отсортированные числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;A[1..r]&amp;lt;/tex&amp;gt;. Этот шаг занимает линейное время, так как сортируется не менее &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел.&lt;br /&gt;
# Помещаем все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;A[j]&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;A[j].set&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Сортировка с использованием O(n log log n) времени и памяти==&lt;br /&gt;
Для сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел в диапазоне &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt; предполагается, что в нашем консервативном алгоритме используется контейнер длины &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log (m + n))&amp;lt;/tex&amp;gt;. Далее везде считается, что все числа упакованы в контейнеры одинаковой длины. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Берем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1/e = 5&amp;lt;/tex&amp;gt; для ЭП-дерева Андерссона. Следовательно, у корня будет &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{1}{5}}&amp;lt;/tex&amp;gt; детей, и каждое ЭП-дерево в каждом ребенке будет иметь &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{4}{5}}&amp;lt;/tex&amp;gt; листьев. В отличие от оригинального дерева, за раз вставляется не один элемент, а &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d^2&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d&amp;lt;/tex&amp;gt; — количество детей узла дерева, в котором числа должны спуститься вниз. Алгоритм полностью опускает все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d^2&amp;lt;/tex&amp;gt; чисел на один уровень. В корне опускаются &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел на следующий уровень. После того, как все числа опустились на следующий уровень, они успешно разделились на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{1} = n^{1/5}&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}, S_{2}, \ldots, S_{t_{1}}&amp;lt;/tex&amp;gt;, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{4}{5}}&amp;lt;/tex&amp;gt; чисел и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i} &amp;lt; S_{j}, i &amp;lt; j&amp;lt;/tex&amp;gt;. Затем, берутся &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{8}{25}}&amp;lt;/tex&amp;gt; чисел из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и опускаются на следующий уровень ЭП-дерева. Это повторяется, пока все числа не опустятся на следующий уровень. На этом шаге числа разделены на &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;t_{2} = n^{\frac{1}{5}}n^{\frac{4}{25}} = n^{\frac{9}{25}}&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T_{1}, T_{2}, \ldots, T_{t_{2}}&amp;lt;/tex&amp;gt;, аналогичных наборам &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt;, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{16}{25}}&amp;lt;/tex&amp;gt; чисел. Теперь числа опускаются дальше в ЭП-дереве.&lt;br /&gt;
&lt;br /&gt;
Нетрудно заметить, что перебалансирока занимает &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; времени с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени на уровень, аналогично стандартному ЭП-дереву Андерссона.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нам следует нумеровать уровни ЭП-дерева с корня, начиная с нуля. Рассмотрим спуск вниз на уровне &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;. Имеется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;t = n^{1 - (\frac{4}{5})^S}&amp;lt;/tex&amp;gt; наборов по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{(\frac{4}{5})^S}&amp;lt;/tex&amp;gt; чисел в каждом. Так как каждый узел на данном уровне имеет &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;p = n^{\frac{1}{5} \cdot (\frac{4}{5})^S}&amp;lt;/tex&amp;gt; детей, то на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s + 1&amp;lt;/tex&amp;gt; уровень опускаются &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;q = n^{\frac{2}{5} \cdot (\frac{4}{5})^S}&amp;lt;/tex&amp;gt; чисел для каждого набора, или всего &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;qt \geqslant n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел для всех наборов за один раз.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Спуск вниз можно рассматривать как сортировку &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел в каждом наборе вместе с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; числами &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}, a_{2}, \ldots, a_{p}&amp;lt;/tex&amp;gt; из ЭП-дерева, так, что эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел разделены в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0}, S_{1}, \ldots, S_{p}&amp;lt;/tex&amp;gt; таких, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; a_{1} &amp;lt; \ldots &amp;lt; a_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел не надо полностью сортировать и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q = p^2&amp;lt;/tex&amp;gt;, то можно использовать [[#lemma6|лемму №6]] для сортировки. Для этого необходимо неконсервативное преимущество, которое получается с помощью [[Сортировка Хана#Signature sorting|signature sorting]]. Для этого используется линейная техника многократного деления (англ. ''multi-dividing technique'').&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; сокращений бит в  [[Сортировка Хана#Signature sorting|signature sorting]] получаем неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{h}{ \log\log n})^g&amp;lt;/tex&amp;gt;. Мы не волнуемся об этих сокращениях до конца потому, что после получения неконсервативного преимущества мы можем переключиться на [[#lemma6|лемму №6]] для завершения разделения &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел с помощью &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел на наборы. Заметим, что по природе битового сокращения начальная задача разделения для каждого набора перешла в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w&amp;lt;/tex&amp;gt; подзадач разделения на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w&amp;lt;/tex&amp;gt; поднаборов для какого-то числа &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Теперь для каждого набора все его поднаборы в подзадачах собираются в один набор. Затем, используя [[#lemma6|лемму №6]], делается разделение. Так как получено неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{h}{\log\log n})^g&amp;lt;/tex&amp;gt; и работа происходит на уровнях не ниже, чем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log\log\log n&amp;lt;/tex&amp;gt;, то алгоритм занимает &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{qt \log\log n}{g(\log h - \log\log\log n) - \log\log\log n}) = O(\log\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В итоге разделились &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; числами в каждый набор. То есть получилось, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; e_{1} &amp;lt; S_{1} &amp;lt; \ldots &amp;lt; e_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;e_{i}&amp;lt;/tex&amp;gt; {{---}} сегмент &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;, полученный с помощью битового сокращения. Такое разделение получилось комбинированием всех поднаборов в подзадачах. Предполагаем, что числа хранятся в массиве &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B&amp;lt;/tex&amp;gt; так, что числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt; предшествуют числам в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{j}&amp;lt;/tex&amp;gt; если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i &amp;lt; j&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;e_{i}&amp;lt;/tex&amp;gt; хранится после &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i - 1}&amp;lt;/tex&amp;gt;, но до &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[i]&amp;lt;/tex&amp;gt; находится в поднаборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[i].subset&amp;lt;/tex&amp;gt;. Чтобы позволить разделению выполниться, для каждого поднабора помещаем все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[j]&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[j].subset&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На это потребуется линейное время и место.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим проблему упаковки, которая решается следующим образом. Считается, что число бит в контейнере &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \geqslant \log\log\log n&amp;lt;/tex&amp;gt;, потому что в противном случае можно использовать radix sort для сортировки чисел. У контейнера есть &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n}&amp;lt;/tex&amp;gt; хешированных значений (сегментов) в себе на уровне &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log h&amp;lt;/tex&amp;gt; в ЭП-дереве. Полное число хешированных бит в контейнере равно &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;(2 \log n)(c \log\log n)&amp;lt;/tex&amp;gt; бит. Хешированные биты в контейнере выглядят как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0^{i}t_{1}0^{i}t_{2} \ldots t&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{\frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{k}&amp;lt;/tex&amp;gt;-ые — хешированные биты, а нули {{---}} это просто нули. Сначала упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров в один и получаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{1} = 0^{j}t_{1, 1}t_{2, 1} \ldots t_{\log\log n, 1}0^{j}t_{1, 2} \ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{  \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{i, k}&amp;lt;/tex&amp;gt;: элемент с номером &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k = 1, 2,  \ldots, &amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n}&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ого контейнера. Используем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; шагов, чтобы упаковать &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{1}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{2} = 0&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;^{\frac{jh}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{1, 1}t_{2, 1} \ldots t_{\log\log n, 1}t_{1, 2}t_{2, 2} \ldots t_{1,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{2,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;. Теперь упакованные хеш-биты занимают &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{c}&amp;lt;/tex&amp;gt; бит. Используем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; времени чтобы распаковать &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{2}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{3, k} = 0&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;^{\frac{jh}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0^{r}t_{k, 1}0^{r}t_{k, 2} \ldots t_{k,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k = 1, 2, \ldots, \log\log n&amp;lt;/tex&amp;gt;. Затем, используя &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; времени, упаковываем эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров в один &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{4} = 0^{r}t_{1, 1}0^{r}t_{1, 2} \ldots t_{1,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0^{r}t_{2, 1} \ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;. Затем, используя &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; шагов, упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{4}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{5} = 0^{s}t_{1, 1}t_{1, 2} \ldots t_{1,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{2, 1}t_{2, 2} \ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;. В итоге используется &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; времени для упаковки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров. Считаем, что время, потраченное на один контейнер — константа.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка подсчетом]]&lt;br /&gt;
* [[Цифровая сортировка]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [http://www.sciencedirect.com/science/article/pii/S019667740300155X Deterministic Sorting in O(n log log n) Time and Linear Space. Yijie Han.]&lt;br /&gt;
* А. Андерссон. Fast deterministic sorting and searching in linear space. Proc. 1996 IEEE Symp. on Foundations of Computer Science. 135-141(1996)&lt;br /&gt;
* [http://dl.acm.org/citation.cfm?id=1236460 A. Andersson, M. Thorup. Dynamic ordered sets with exponential search trees.]&lt;br /&gt;
* [[wikipedia:en:Integer_sorting|Wikipedia {{---}} Integer sorting]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Сортировка]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%A5%D0%B0%D0%BD%D0%B0&amp;diff=47999</id>
		<title>Сортировка Хана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D0%A5%D0%B0%D0%BD%D0%B0&amp;diff=47999"/>
				<updated>2015-06-07T17:24:07Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Сортировка Хана''' (англ. ''Hansort'') {{---}} сложный алгоритм сортировки целых чисел со сложностью &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов для сортировки.&lt;br /&gt;
&lt;br /&gt;
Данная статья писалась на основе брошюры Хана (англ. ''Yijie Han''), посвященной этой сортировке.&lt;br /&gt;
&lt;br /&gt;
== Описание ==&lt;br /&gt;
Алгоритм построен на основе '''экспоненциального поискового дерева Андерсона''' (англ. ''Andersson's exponential search tree''). Сортировка происходит за счет вставки целых чисел в экспоненциальное поисковое дерево (''далее {{---}} ЭП-дерево'').&lt;br /&gt;
&lt;br /&gt;
== Экспоненциальное поисковое дерево Андерсона ==&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = '''ЭП-дерево''' {{---}} это дерево поиска, в котором все ключи хранятся в листьях этого дерева и количество детей у каждого узла уменьшается экспоненциально от глубины узла.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Файл:Exp-tree.png|400px|thumb|right|Общая структура ЭП-дерева]]&lt;br /&gt;
&lt;br /&gt;
Структура ЭП-дерева:&lt;br /&gt;
&lt;br /&gt;
1) Корень имеет &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\Theta (n^e)&amp;lt;/tex&amp;gt; сыновей &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;( 0 &amp;lt; e &amp;lt; 1 )&amp;lt;/tex&amp;gt;. Все сыновья являются ЭП-деревьями.&lt;br /&gt;
&lt;br /&gt;
2) Каждое поддерево корня имеет &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\Theta(n^{1-e})&amp;lt;/tex&amp;gt; сыновей.&lt;br /&gt;
&lt;br /&gt;
В этом дереве &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; уровней. При нарушении баланса дерева необходимо балансирование, которое требует &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; времени при &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; вставленных целых числах. Такое время достигается за счет вставки чисел группами, а не поодиночке, как изначально предлагал Андерссон.&lt;br /&gt;
&lt;br /&gt;
==Определения== &lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 '''Контейнер''' {{---}} объект, в которым хранятся наши данные. Например: 32-битные и 64-битные числа, массивы, вектора.}}&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Алгоритм, сортирующий &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел из множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt;, называется '''консервативным''', если длина контейнера (число бит в контейнере) равна &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log(m + n))&amp;lt;/tex&amp;gt;. Если длина больше, то алгоритм '''неконсервативный'''.&lt;br /&gt;
 }}&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Если сортируются целые числа из множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt; с длиной контейнера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log (m + n)&amp;lt;/tex&amp;gt; с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \geqslant 1&amp;lt;/tex&amp;gt;, тогда сортировка происходит с '''неконсервативным преимуществом''' &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Для множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; определим&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\min(S) = \min\limits_{a \in S} a&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\max(S) = \max\limits_{a \in S} a&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S1 &amp;lt; S2&amp;lt;/tex&amp;gt; если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\max(S1) \leqslant \min(S2)&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{ Определение | definition =&lt;br /&gt;
 Предположим, есть набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел, которые уже отсортированы как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}, a_{2}, \ldots, a_{p}&amp;lt;/tex&amp;gt; и набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{1}, b_{2}, \ldots, b_{q}&amp;lt;/tex&amp;gt;. Тогда '''разделением''' &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; числами называется &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0}, S_{1}, \ldots, S_{p}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; a_{1} &amp;lt; S_{1} &amp;lt; \ldots &amp;lt; a_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Леммы==&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma1&lt;br /&gt;
|about = № 1&lt;br /&gt;
|statement = &lt;br /&gt;
Даны целые числа &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b \geqslant s \geqslant 0&amp;lt;/tex&amp;gt;, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; является подмножеством множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, \ldots, 2^b - 1\}&amp;lt;/tex&amp;gt;, содержащим &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; элементов, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t \geqslant 2^{-s + 1}С^k_{n}&amp;lt;/tex&amp;gt;. Функция &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}&amp;lt;/tex&amp;gt;, принадлежащая &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;H_{b,s}&amp;lt;/tex&amp;gt;, может быть выбрана за время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(bn^2)&amp;lt;/tex&amp;gt; так, что количество коллизий &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;coll(h_{a}, T) \leqslant t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma2&lt;br /&gt;
|about = № 2&lt;br /&gt;
|statement = &lt;br /&gt;
Выбор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;-ого наибольшего числа среди &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел, упакованных в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнеров, может быть сделан за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log g}{g})&amp;lt;/tex&amp;gt; и с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти. В том числе, так  может быть найдена медиана.&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Так как возможно делать попарное сравнение &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел в одном контейнере с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; числами в другом и извлекать большие числа из одного контейнера и меньшие из другого за константное время, возможно упаковать медианы из первого, второго, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;-ого чисел из 5 контейнеров в один контейнер за константное время. Таким образом, набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; из медиан теперь содержится в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{5g}&amp;lt;/tex&amp;gt; контейнерах. Рекурсивно находим медиану &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;m&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;. Используя &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;m&amp;lt;/tex&amp;gt;, уберем хотя бы &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{4}&amp;lt;/tex&amp;gt; чисел среди &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt;. Затем упакуем оставшиеся из &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнеров в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{3n}{4g}&amp;lt;/tex&amp;gt; контейнеров и затем продолжим рекурсию.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma3&lt;br /&gt;
|about = № 3&lt;br /&gt;
|statement = &lt;br /&gt;
Если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; целых чисел, в сумме использующих &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит, упакованы в один контейнер, тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнерах могут быть отсортированы за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log g}{g})&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Так как используется только &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит в каждом контейнере для хранения &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел, используем bucket sort, чтобы отсортировать все контейнеры, представляя каждый как число, что занимает &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; времени и памяти. Так как используется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит на контейнер, понадобится &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; шаблонов для всех контейнеров. Затем поместим &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;g &amp;lt; \frac{\log n}{2}&amp;lt;/tex&amp;gt; контейнеров с одинаковым шаблоном в одну группу. Для каждого шаблона останется не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g - 1&amp;lt;/tex&amp;gt; контейнеров, которые не смогут образовать группу. Поэтому не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}(g - 1)&amp;lt;/tex&amp;gt; контейнеров не смогут сформировать группу. Для каждой группы помещаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-е число во всех &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнерах в один. Таким образом берутся &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;-целых векторов и получаются &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;-целых векторов, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ый вектор содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ое число из входящего вектора. Эта транспозиция может быть сделана за время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(g \log g)&amp;lt;/tex&amp;gt;, с использованием &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(g)&amp;lt;/tex&amp;gt; памяти. Для всех групп это занимает время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log g}{g})&amp;lt;/tex&amp;gt;, с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
Для контейнеров вне групп (которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}(g - 1)&amp;lt;/tex&amp;gt; штук) разбираем и собираем заново контейнеры. На это потребуется не более &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; времени и памяти. После всего этого используем карманную сортировку вновь для сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; контейнеров. Таким образом, все числа отсортированы.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заметим, что когда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g = O( \log n)&amp;lt;/tex&amp;gt;, сортировка &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнеров произойдет за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O((\frac{n}{g})&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n)&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти. Выгода очевидна.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma4&lt;br /&gt;
|about = № 4&lt;br /&gt;
|statement = &lt;br /&gt;
Примем, что каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt; \log m &amp;gt; \log n&amp;lt;/tex&amp;gt; бит, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{g}&amp;lt;/tex&amp;gt; бит, упакованы в один контейнер. Если каждое число имеет маркер, содержащий &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2g}&amp;lt;/tex&amp;gt; бит, и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; маркеров упакованы в один контейнер таким же образом&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;^*&amp;lt;/tex&amp;gt;, что и числа, тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнерах могут быть отсортированы по их маркерам за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log\log n}{g})&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
(*): если число &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; упаковано как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;-ое число в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt;-ом контейнере для чисел, тогда маркер для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; упакован как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;-ый маркер в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt;-ом контейнере для маркеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Контейнеры для маркеров могут быть отсортированы с помощью bucket sort потому, что каждый контейнер использует &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит. Сортировка сгруппирует контейнеры для чисел как в [[#lemma3|лемме №3]]. Перемещаем каждую группу контейнеров для чисел.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma5&lt;br /&gt;
|about = № 5&lt;br /&gt;
|statement =&lt;br /&gt;
Предположим, что каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \log\log n &amp;gt; \log n&amp;lt;/tex&amp;gt; бит, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; чисел, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{g}&amp;lt;/tex&amp;gt; бит, упакованы в один контейнер, что каждое число имеет маркер, содержащий &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2g}&amp;lt;/tex&amp;gt; бит, и что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; маркеров упакованы в один контейнер тем же образом что и числа. Тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{g}&amp;lt;/tex&amp;gt; контейнерах могут быть отсортированы по своим маркерам за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; с использованием &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Заметим, что несмотря на то, что длина контейнера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \log\log n&amp;lt;/tex&amp;gt; бит, всего &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит используется для хранения упакованных чисел. Так же как в [[#lemma3|лемме №3]] и [[#lemma4|лемме №4]] сортируем контейнеры упакованных маркеров с помощью bucket sort. Для того, чтобы перемещать контейнеры чисел, помещаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; вместо &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнеров чисел в одну группу. Для транспозиции чисел в группе, содержащей &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; контейнеров, упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; контейнеров в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt;, упаковывая &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров в один. Далее делаем транспозицию над &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнерами. Таким образом перемещение занимает всего &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(g \log\log n)&amp;lt;/tex&amp;gt; времени для каждой группы и &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt; времени для всех чисел. После завершения транспозиции, распаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; контейнеров в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \log\log n&amp;lt;/tex&amp;gt; контейнеров.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Заметим, что если длина контейнера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \log\log n&amp;lt;/tex&amp;gt; и только &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит используется для упаковки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g \leqslant \log n&amp;lt;/tex&amp;gt; чисел в один контейнер, тогда выбор в [[#lemma2|лемме №2]] может быть сделан за время и память &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt;, потому что упаковка в доказательстве [[#lemma2|лемме №2]] теперь может быть сделана за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{g})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma6&lt;br /&gt;
|about = № 6&lt;br /&gt;
|statement = &lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел можно отсортировать в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{\sqrt{n}}&amp;lt;/tex&amp;gt; таким образом, что в каждом наборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; чисел и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i} &amp;lt; S_{j}&amp;lt;/tex&amp;gt; при &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i &amp;lt; j&amp;lt;/tex&amp;gt;, за время &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log\log n} {\log k})&amp;lt;/tex&amp;gt; и место &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; с неконсервативным преимуществом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log\log n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|proof = &lt;br /&gt;
Алгоритм сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; наборов, представленный ниже, является доказательством данной леммы. &lt;br /&gt;
&lt;br /&gt;
Постановка задачи и решение некоторых проблем:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим проблему сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел из множества &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt; наборов, как в условии леммы. Предполагаем, что каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log\log n \log m&amp;lt;/tex&amp;gt; бит и хранит число в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит. Поэтому неконсервативное преимущество {{---}} &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log \log n&amp;lt;/tex&amp;gt;. Также предполагаем, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \geqslant \log n \log\log n&amp;lt;/tex&amp;gt;. Иначе можно использовать radix sort для сортировки за время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; и линейную память. Делим &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит, используемых для представления каждого числа, в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; блоков. Таким образом, каждый блок содержит как минимум &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; бит. &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ый блок содержит с &lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{i \log m} {\log n}&amp;lt;/tex&amp;gt;-ого по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{(i + 1) \log m} {\log n - 1})&amp;lt;/tex&amp;gt;-ый биты. Биты считаются с наименьшего бита, начиная с нуля. Теперь у нас имеется &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log n&amp;lt;/tex&amp;gt;-уровневый алгоритм, который работает следующим образом:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На каждой стадии работаем с одним блоком бит. Назовем эти блоки маленькими числами (далее м.ч.), потому что каждое м.ч. теперь содержит только &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{\log n}&amp;lt;/tex&amp;gt; бит. Каждое число представлено и соотносится с м.ч., над которым работаем в данный момент. Положим, что нулевая стадия работает с самым большим блоком (блок номер &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n - 1&amp;lt;/tex&amp;gt;). Предполагаем, что биты этих м.ч. упакованы в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{\log n}&amp;lt;/tex&amp;gt; контейнеров с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; м.ч. упакованными в один контейнер. Пренебрегая временем, потраченным на эту упаковку, считаем, что она бесплатна. По [[#lemma2|лемме №2]] находим медиану этих &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; м.ч. за время и память &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n}{\log n})&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; {{---}} это найденная медиана. Тогда &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; м.ч. могут быть разделены на не более чем три группы: &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{3}&amp;lt;/tex&amp;gt;. &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt; содержит м.ч., которые меньше &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt; содержит м.ч., равные &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{3}&amp;lt;/tex&amp;gt; содержит м.ч., большие &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;. Также мощность &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{3} &amp;lt;/tex&amp;gt; не превосходит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n/2&amp;lt;/tex&amp;gt;. Мощность &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt; может быть любой. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S'_{2}&amp;lt;/tex&amp;gt; {{---}} это набор чисел, у которых наибольший блок находится в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{2}&amp;lt;/tex&amp;gt;. Тогда убираем из дальнейшего рассмотрения &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{\log n}&amp;lt;/tex&amp;gt; бит (наибольший блок) из каждого числа, принадлежащего &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S'_{2}&amp;lt;/tex&amp;gt;. Таким образом, после первой стадии каждое число находится в наборе размера не большего половины размера начального набора или один из блоков в числе убран из дальнейшего рассмотрения. Так как в каждом числе только &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; блоков, для каждого числа потребуется не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; стадий, чтобы поместить его в набор половинного размера. За &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log n&amp;lt;/tex&amp;gt; стадий все числа будут отсортированы. Так как на каждой стадии работаем с &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{\log n}&amp;lt;/tex&amp;gt; контейнерами, то игнорируя время, необходимое на упаковку м.ч. в контейнеры и помещение м.ч. в нужный набор, затрачивается &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени из-за &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log n&amp;lt;/tex&amp;gt; стадий.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложная часть алгоритма заключается в том, как поместить м.ч. в набор, которому принадлежит соответствующее число, после предыдущих операций деления набора в нашем алгоритме. Предположим, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел уже поделены в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;e&amp;lt;/tex&amp;gt; наборов. Используем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log e&amp;lt;/tex&amp;gt; битов чтобы сделать марки для каждого набора. Теперь используем [[#lemma5|лемме №5]]. Полный размер маркера для каждого контейнера должен быть &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt;, и маркер использует &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log e&amp;lt;/tex&amp;gt; бит, значит количество маркеров &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; в каждом контейнере должно быть не более &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2\log e}&amp;lt;/tex&amp;gt;. В дальнейшем, так как &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;g = \frac{\log n}{2 \log e}&amp;lt;/tex&amp;gt;, м.ч. должны влезать в контейнер. Каждый контейнер содержит &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log\log n \log n&amp;lt;/tex&amp;gt; блоков, каждое м.ч. может содержать &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{k \log n}{g}) = O(k \log e)&amp;lt;/tex&amp;gt; блоков. Заметим, что используется неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; для [[#lemma5|лемме №5]] Поэтому предполагается, что &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2 \log e}&amp;lt;/tex&amp;gt; м.ч., в каждом из которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков битов числа, упакованны в один контейнер. Для каждого м.ч. используется маркер из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log e&amp;lt;/tex&amp;gt; бит, который показывает, к какому набору он принадлежит. Предполагаем, что маркеры так же упакованы в контейнеры, как и м.ч. Так как каждый контейнер для маркеров содержит &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2 \log e}&amp;lt;/tex&amp;gt; маркеров, то для каждого контейнера требуется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{2}&amp;lt;/tex&amp;gt; бит. Таким образом, [[#lemma5|лемма №5]] может быть применена для помещения м.ч. в наборы, которым они принадлежат. Так как используется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log e}{ \log n})&amp;lt;/tex&amp;gt; контейнеров, то время, необходимое для помещения м.ч. в их наборы, равно &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log e}{ \log n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Стоит отметить, что процесс помещения нестабилен, т.к. основан на алгоритме из [[#lemma5|леммы №5]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
При таком помещении сразу возникает следующая проблема.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим число &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt;, которое является &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ым в наборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;. Рассмотрим блок &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; (назовем его &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'&amp;lt;/tex&amp;gt;), который является &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ым м.ч. в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;. Когда используется вышеописанный метод перемещения нескольких следующих блоков &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a&amp;lt;/tex&amp;gt; (назовем это &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a''&amp;lt;/tex&amp;gt;) в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a''&amp;lt;/tex&amp;gt; просто перемещен на позицию в наборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;, но не обязательно на позицию &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt; (где расположен &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'&amp;lt;/tex&amp;gt;). Если значение блока &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'&amp;lt;/tex&amp;gt; одинаково для всех чисел в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt;, то это не создаст проблемы потому, что блок одинаков вне зависимости от того в какое место в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; помещен &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a''&amp;lt;/tex&amp;gt;. Иначе у нас возникает проблема дальнейшей сортировки. Поэтому поступаем следующим образом: На каждой стадии числа в одном наборе работают на общем блоке, который назовем &amp;quot;текущий блок набора&amp;quot;. Блоки, которые предшествуют текущему блоку содержат важные биты и идентичны для всех чисел в наборе. Когда помещаем больше бит в набор, последующие блоки помещаются в набор вместе с текущим блоком. Так вот, в вышеописанном процессе помещения предполагается, что самый значимый блок среди &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков {{---}} это текущий блок. Таким образом, после того, как эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков помещены в набор, изначальный текущий блок удаляется, потому что известно, что эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоков перемещены в правильный набор, и нам не важно где находился начальный текущий блок. Тот текущий блок находится в перемещенных &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k \log e&amp;lt;/tex&amp;gt; блоках.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Стоит отметить, что после нескольких уровней деления размер наборов станет маленьким. Леммы [[#lemma3|3]], [[#lemma4|4]], [[#lemma5|5]] расчитаны на не очень маленькие наборы. Но поскольку сортируется набор из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; элементов в наборы размера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;, то проблем быть не должно.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Алгоритм сортировки===&lt;br /&gt;
&lt;br /&gt;
Algorithm &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;level&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{0}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{t}&amp;lt;/tex&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;advantage&amp;lt;/tex&amp;gt; {{---}} это неконсервативное преимущество равное &amp;lt;tex&amp;gt;k\log\log n&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;a_{i}&amp;lt;/tex&amp;gt;-ые это входящие целые числа в наборе, которые надо отсортировать, &amp;lt;tex&amp;gt;level&amp;lt;/tex&amp;gt; это уровень рекурсии.&lt;br /&gt;
&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;level&amp;lt;/tex&amp;gt; равен &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; тогда изучаем размер набора. Если размер меньше или равен &amp;lt;tex&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;return&amp;lt;/tex&amp;gt;. Иначе делим этот набор в &amp;lt;tex&amp;gt;\leqslant&amp;lt;/tex&amp;gt; 3 набора, используя [[#lemma2|лемму №2]], чтобы найти медиану, а затем используем [[#lemma5|лемму №5]] для сортировки. Для набора, где все элементы равны медиане, не рассматриваем текущий блок и текущим блоком делаем следующий. Создаем маркер, являющийся номером набора для каждого из чисел (0, 1 или 2). Затем направляем маркер для каждого числа назад к месту, где число находилось в начале. Также направляем двубитное число для каждого входного числа, указывающее на текущий блок.&lt;br /&gt;
# От &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;u = 1&amp;lt;/tex&amp;gt; до &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k&amp;lt;/tex&amp;gt;&lt;br /&gt;
## Упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{i}&amp;lt;/tex&amp;gt;-ый в часть из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1/k&amp;lt;/tex&amp;gt;-ых номеров контейнеров. Где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{i}&amp;lt;/tex&amp;gt; содержит несколько непрерывных блоков, которые состоят из &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{1}{k}&amp;lt;/tex&amp;gt;-ых битов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;. При этом у &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{i}&amp;lt;/tex&amp;gt; текущий блок это самый крупный блок.&lt;br /&gt;
## Вызываем &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;level - 1&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{0}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a^{(u)}_{t}&amp;lt;/tex&amp;gt;). Когда алгоритм возвращается из этой рекурсии, маркер, показывающий для каждого числа, к какому набору это число относится, уже направлен назад к месту, где число находится во входных данных. Число, имеющее наибольшее число бит в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;, показывающее на текущий блок в нем, так же направлено назад к &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
## Отправляем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;-ые к их наборам, используя [[#lemma5|лемму №5]].&lt;br /&gt;
&lt;br /&gt;
Algorithm IterateSort&lt;br /&gt;
Call &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log_{k}((\log n)/4)&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{0}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{n - 1}&amp;lt;/tex&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
от 1 до 5&lt;br /&gt;
# Помещаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; в соответствующий набор с помощью блочной сортировки (англ. ''bucket sort''), потому что наборов около &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\sqrt{n}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Для каждого набора &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S = &amp;lt;/tex&amp;gt;{&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i_{0}}, a_{i_{1}}, \ldots, a_{i_{t}}&amp;lt;/tex&amp;gt;}, если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t &amp;gt; \sqrt{n}&amp;lt;/tex&amp;gt;, вызываем &amp;lt;tex&amp;gt;Sort(advantage&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log_{k}(\frac{\log n}{4})&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i_{0}}, a_{i_{1}}, \ldots, a_{i_{t}}&amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Время работы алгоритма &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{n \log\log n}{\log k})&amp;lt;/tex&amp;gt;, что доказывает лемму.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Уменьшение числа бит в числах==&lt;br /&gt;
Один из способов ускорить сортировку {{---}} уменьшить число бит в числе. Один из способов уменьшить число бит в числе {{---}} использовать деление пополам (эту идею впервые подал van Emde Boas). Деление пополам заключается в том, что количество оставшихся бит в числе уменьшается в 2 раза. Это быстрый способ, требующий &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(m)&amp;lt;/tex&amp;gt; памяти. Для своего дерева Андерссон использует хеширование, что позволяет сократить количество памяти до &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Для того чтобы еще ускорить алгоритм, необходимо упаковать несколько чисел в один контейнер, чтобы затем за константное количество шагов произвести хеширование для всех чисел, хранимых в контейнере. Для этого используется хеш-функция для хеширования &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел в таблицу размера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; за константное время без коллизий. Для этого используется модифицированная хеш-функция авторства: Dierzfelbinger и Raman.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Алгоритм: Пусть целое число &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b \geqslant 0&amp;lt;/tex&amp;gt; и пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U = \{0, \ldots, 2^b - 1\}&amp;lt;/tex&amp;gt;. Класс &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;H_{b,s}&amp;lt;/tex&amp;gt; хеш-функций из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, \ldots, 2^s - 1\}&amp;lt;/tex&amp;gt; определен как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;H_{b,s} = \{h_{a} \mid 0 &amp;lt; a &amp;lt; 2^b, a \equiv 1 (\bmod 2)\}&amp;lt;/tex&amp;gt; и для всех &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;x&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U&amp;lt;/tex&amp;gt;: &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}(x) = (ax&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\bmod&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^b)&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;div&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^{b - s}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм базируется на [[#lemma1|лемме №1]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Взяв &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s = 2 \log n&amp;lt;/tex&amp;gt;, получаем хеш-функцию &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}&amp;lt;/tex&amp;gt;, которая захеширует &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;U&amp;lt;/tex&amp;gt; в таблицу размера &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; без коллизий. Очевидно, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}(x)&amp;lt;/tex&amp;gt; может быть посчитана для любого &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;x&amp;lt;/tex&amp;gt; за константное время. Если упаковать несколько чисел в один контейнер так, что они разделены несколькими битами нулей, то можно применить &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h_{a}&amp;lt;/tex&amp;gt; ко всему контейнеру, и в результате все хеш-значения для всех чисел в контейнере будут посчитаны. Заметим, что это возможно только потому, что в вычисление хеш-значения вовлечены только (&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\bmod&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^b&amp;lt;/tex&amp;gt;) и (&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;div&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2^{b - s}&amp;lt;/tex&amp;gt;). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Такая хеш-функция может быть найдена за &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следует отметить, что, несмотря на размер таблицы &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;, потребность в памяти не превышает &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt;, потому что хеширование используется только для уменьшения количества бит в числе.&lt;br /&gt;
&lt;br /&gt;
==Сортировка по ключу==&lt;br /&gt;
Предположим, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел должны быть отсортированы, и в каждом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит. Будем считать, что в каждом числе есть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h&amp;lt;/tex&amp;gt; сегментов, в каждом из которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m/h&amp;lt;/tex&amp;gt; бит. Теперь применяем хеширование ко всем сегментам и получаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2h \log n&amp;lt;/tex&amp;gt; бит хешированных значений для каждого числа. После сортировки на хешированных значениях для всех начальных чисел начальная задача по сортировке &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит в каждом стала задачей по сортировке &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m/h&amp;lt;/tex&amp;gt; бит в каждом.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Также рассмотрим проблему последующего разделения. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{2}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{p}&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; {{---}} множество чисeл. Необходимо разделить &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; наборов, таких, что: &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; a_{1} &amp;lt; S_{1} &amp;lt; a_{2} &amp;lt; \ldots &amp;lt; a_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;. Так как используется '''сортировка по ключу''' (англ. ''signature sorting'') то перед тем, как делать вышеописанное разделение, необходимо поделить биты в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h&amp;lt;/tex&amp;gt; сегментов и взять некоторые из них. Так же делим биты для каждого числа из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; и оставляем только один в каждом числе. По существу, для каждого &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; берутся все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;h&amp;lt;/tex&amp;gt; сегментов. Если соответствующие сегменты &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{j}&amp;lt;/tex&amp;gt; совпадают, то нам понадобится только один. Сегмент, который берется для числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; это сегмент, который выделяется из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;. Таким образом, начальная задача о разделении &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; чисел по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m&amp;lt;/tex&amp;gt; бит преобразуется в несколько задач на разделение с числами по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log m}{h}&amp;lt;/tex&amp;gt; бит.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Пример''':&lt;br /&gt;
[[Файл:Han-example.png|500px|thumb]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1} = 3, a_{2} = 5, a_{3} = 7, a_{4} = 10, S = \{1, 4, 6, 8, 9, 13, 14\}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Делим числа на два сегмента. Для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt; получим верхний сегмент &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{2}&amp;lt;/tex&amp;gt; {{---}} верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{3}&amp;lt;/tex&amp;gt; {{---}} верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{4}&amp;lt;/tex&amp;gt; {{---}} верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2&amp;lt;/tex&amp;gt;, нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2&amp;lt;/tex&amp;gt;. Для элементов из S получим: для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;, так как он выделяется из нижнего сегмента &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;4&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;8&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;9&amp;lt;/tex&amp;gt; нижний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;13&amp;lt;/tex&amp;gt; верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;; для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;14&amp;lt;/tex&amp;gt; верхний &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;. Теперь все верхние сегменты, нижние сегменты &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;3&amp;lt;/tex&amp;gt;, нижние сегменты &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;4, 5, 6, 7,&amp;lt;/tex&amp;gt; нижние сегменты  &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;8, 9, 10&amp;lt;/tex&amp;gt; формируют &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;4&amp;lt;/tex&amp;gt; новые задачи на разделение.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Использование '''сортировки по ключу''' в данном алгоритме:&lt;br /&gt;
&lt;br /&gt;
Есть набор &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел, которые отсортированы как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}, a_{2}, \ldots, a_{p}&amp;lt;/tex&amp;gt;. Используем числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T&amp;lt;/tex&amp;gt; для разделения набора &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{1}, b_{2}, \ldots, b_{q}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0}, S_{1}, \ldots, S_{p}&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;h = \frac{\log n}{c \log p}&amp;lt;/tex&amp;gt; для константы &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;c &amp;gt; 1&amp;lt;/tex&amp;gt;. (&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n \log p}&amp;lt;/tex&amp;gt;)-битные числа могут храниться в одном контейнере, содержащим &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит. Сначала рассматриваем биты в каждом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; и каждом &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{i}&amp;lt;/tex&amp;gt; как сегменты одинаковой длины &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h} {\log\log n}&amp;lt;/tex&amp;gt;. Рассматриваем сегменты как числа. Чтобы получить неконсервативное преимущество для сортировки, числа в этих контейнерах (&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;-ом и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{i}&amp;lt;/tex&amp;gt;-ом) хешируются, и получается &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n}&amp;lt;/tex&amp;gt; хешированных значений в одном контейнере. При вычислении хеш-значений сегменты не влияют друг на друга, можно даже отделить четные и нечетные сегменты в два контейнера. Не умаляя общности считаем, что хеш-значения считаются за константное время. Затем, посчитав значения, два контейнера объединяем в один. Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a'_{i}&amp;lt;/tex&amp;gt; {{---}} хеш-контейнер для &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;, аналогично &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b'_{i}&amp;lt;/tex&amp;gt;. В сумме хеш-значения имеют &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит, хотя эти значения разделены на сегменты по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{ \log\log n}&amp;lt;/tex&amp;gt; бит в каждом контейнере. Между сегментами получаются пустоты, которые забиваются нулями. Сначала упаковываются все сегменты в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит. Потом рассматривается каждый хеш-контейнер как число, и эти хеш-контейнеры сортируются за линейное время (сортировка будет рассмотрена чуть позже). После этой сортировки биты в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;b_{i}&amp;lt;/tex&amp;gt; разрезаны на &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log\log n}{h}&amp;lt;/tex&amp;gt; сегментов. Таким образом, получилось дополнительное мультипликативное преимущество (англ. ''additional multiplicative advantage'') в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h} {\log\log n}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
После того, как вышеописанный процесс повторится &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; раз, получится неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{h} {\log\log n})^g&amp;lt;/tex&amp;gt; раз, в то время как потрачено только &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(gqt)&amp;lt;/tex&amp;gt; времени, так как каждое многократное деление происходит за линейное время &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(qt)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Хеш-функция, которая используется, находится следующим образом. Будут хешироватся сегменты, &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{\log\log n}{h}&amp;lt;/tex&amp;gt;-ые, &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{\log\log n}{h})^2&amp;lt;/tex&amp;gt;-ые, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots&amp;lt;/tex&amp;gt; по счету в числе. Хеш-функцию для &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{\log\log n}{h})^t&amp;lt;/tex&amp;gt;-ых по счету сегментов, получаем нарезанием всех &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел на &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{\log\log n}{h})^t&amp;lt;/tex&amp;gt; сегментов. Рассматривая каждый сегмент как число, получаем &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;p(\frac{\log\log n}{h})^t&amp;lt;/tex&amp;gt; чисел. Затем получаем одну хеш-функцию для этих чисел. Так как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t &amp;lt; \log n&amp;lt;/tex&amp;gt;, то получится не более &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log n&amp;lt;/tex&amp;gt; хеш-функций.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Рассмотрим сортировку за линейное время, о которой было упомянуто ранее. Предполагается, что хешированные значения для каждого контейнера упакованы в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит. Есть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt; наборов, в каждом из которых &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q + p&amp;lt;/tex&amp;gt; хешированных контейнеров по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит в каждом. Эти контейнеры должны быть отсортированы в каждом наборе. Комбинируя все хеш-контейнеры в один pool, сортируем следующим образом.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Операция '''сортировки за линейное время''' (англ. ''Linear-Time-Sort'')&lt;br /&gt;
&lt;br /&gt;
Входные данные: &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;r &amp;gt; = n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt;, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}.value&amp;lt;/tex&amp;gt; — значение числа &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt;, в котором &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{2 \log n}{c \log\log n}&amp;lt;/tex&amp;gt; бит, &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}.set&amp;lt;/tex&amp;gt; — набор, в котором находится &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt;. Следует отметить, что всего есть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t&amp;lt;/tex&amp;gt; наборов.&lt;br /&gt;
&lt;br /&gt;
# Сортируем все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}&amp;lt;/tex&amp;gt; по &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d_{i}.value&amp;lt;/tex&amp;gt;, используя bucket sort. Пусть все отсортированные числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;A[1..r]&amp;lt;/tex&amp;gt;. Этот шаг занимает линейное время, так как сортируется не менее &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел.&lt;br /&gt;
# Помещаем все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;A[j]&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;A[j].set&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Сортировка с использованием O(n log log n) времени и памяти==&lt;br /&gt;
Для сортировки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;n&amp;lt;/tex&amp;gt; целых чисел в диапазоне &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\{0, 1, \ldots, m - 1\}&amp;lt;/tex&amp;gt; предполагается, что в нашем консервативном алгоритме используется контейнер длины &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log (m + n))&amp;lt;/tex&amp;gt;. Далее везде считается, что все числа упакованы в контейнеры одинаковой длины. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Берем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;1/e = 5&amp;lt;/tex&amp;gt; для ЭП-дерева Андерссона. Следовательно, у корня будет &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{1}{5}}&amp;lt;/tex&amp;gt; детей, и каждое ЭП-дерево в каждом ребенке будет иметь &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{4}{5}}&amp;lt;/tex&amp;gt; листьев. В отличие от оригинального дерева, за раз вставляется не один элемент, а &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d^2&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d&amp;lt;/tex&amp;gt; — количество детей узла дерева, в котором числа должны спуститься вниз. Алгоритм полностью опускает все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;d^2&amp;lt;/tex&amp;gt; чисел на один уровень. В корне опускаются &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел на следующий уровень. После того, как все числа опустились на следующий уровень, они успешно разделились на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{1} = n^{1/5}&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{1}, S_{2}, \ldots, S_{t_{1}}&amp;lt;/tex&amp;gt;, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{4}{5}}&amp;lt;/tex&amp;gt; чисел и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i} &amp;lt; S_{j}, i &amp;lt; j&amp;lt;/tex&amp;gt;. Затем, берутся &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{8}{25}}&amp;lt;/tex&amp;gt; чисел из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и опускаются на следующий уровень ЭП-дерева. Это повторяется, пока все числа не опустятся на следующий уровень. На этом шаге числа разделены на &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;t_{2} = n^{\frac{1}{5}}n^{\frac{4}{25}} = n^{\frac{9}{25}}&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;T_{1}, T_{2}, \ldots, T_{t_{2}}&amp;lt;/tex&amp;gt;, аналогичных наборам &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt;, в каждом из которых &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{\frac{16}{25}}&amp;lt;/tex&amp;gt; чисел. Теперь числа опускаются дальше в ЭП-дереве.&lt;br /&gt;
&lt;br /&gt;
Нетрудно заметить, что перебалансирока занимает &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n \log\log n)&amp;lt;/tex&amp;gt; времени с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени на уровень, аналогично стандартному ЭП-дереву Андерссона.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нам следует нумеровать уровни ЭП-дерева с корня, начиная с нуля. Рассмотрим спуск вниз на уровне &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s&amp;lt;/tex&amp;gt;. Имеется &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;t = n^{1 - (\frac{4}{5})^S}&amp;lt;/tex&amp;gt; наборов по &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;n^{(\frac{4}{5})^S}&amp;lt;/tex&amp;gt; чисел в каждом. Так как каждый узел на данном уровне имеет &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;p = n^{\frac{1}{5} \cdot (\frac{4}{5})^S}&amp;lt;/tex&amp;gt; детей, то на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;s + 1&amp;lt;/tex&amp;gt; уровень опускаются &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;q = n^{\frac{2}{5} \cdot (\frac{4}{5})^S}&amp;lt;/tex&amp;gt; чисел для каждого набора, или всего &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;qt \geqslant n^{\frac{2}{5}}&amp;lt;/tex&amp;gt; чисел для всех наборов за один раз.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Спуск вниз можно рассматривать как сортировку &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел в каждом наборе вместе с &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; числами &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{1}, a_{2}, \ldots, a_{p}&amp;lt;/tex&amp;gt; из ЭП-дерева, так, что эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел разделены в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p + 1&amp;lt;/tex&amp;gt; наборов &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0}, S_{1}, \ldots, S_{p}&amp;lt;/tex&amp;gt; таких, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; a_{1} &amp;lt; \ldots &amp;lt; a_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Так как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел не надо полностью сортировать и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q = p^2&amp;lt;/tex&amp;gt;, то можно использовать [[#lemma6|лемму №6]] для сортировки. Для этого необходимо неконсервативное преимущество, которое получается с помощью [[Сортировка Хана#Signature sorting|signature sorting]]. Для этого используется линейная техника многократного деления (англ. ''multi-dividing technique'').&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;g&amp;lt;/tex&amp;gt; сокращений бит в  [[Сортировка Хана#Signature sorting|signature sorting]] получаем неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{h}{ \log\log n})^g&amp;lt;/tex&amp;gt;. Мы не волнуемся об этих сокращениях до конца потому, что после получения неконсервативного преимущества мы можем переключиться на [[#lemma6|лемму №6]] для завершения разделения &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел с помощью &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; чисел на наборы. Заметим, что по природе битового сокращения начальная задача разделения для каждого набора перешла в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w&amp;lt;/tex&amp;gt; подзадач разделения на &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w&amp;lt;/tex&amp;gt; поднаборов для какого-то числа &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Теперь для каждого набора все его поднаборы в подзадачах собираются в один набор. Затем, используя [[#lemma6|лемму №6]], делается разделение. Так как получено неконсервативное преимущество в &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;(\frac{h}{\log\log n})^g&amp;lt;/tex&amp;gt; и работа происходит на уровнях не ниже, чем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log\log\log n&amp;lt;/tex&amp;gt;, то алгоритм занимает &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;O(\frac{qt \log\log n}{g(\log h - \log\log\log n) - \log\log\log n}) = O(\log\log n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
В итоге разделились &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;q&amp;lt;/tex&amp;gt; чисел &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;p&amp;lt;/tex&amp;gt; числами в каждый набор. То есть получилось, что &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{0} &amp;lt; e_{1} &amp;lt; S_{1} &amp;lt; \ldots &amp;lt; e_{p} &amp;lt; S_{p}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;e_{i}&amp;lt;/tex&amp;gt; {{---}} сегмент &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;a_{i}&amp;lt;/tex&amp;gt;, полученный с помощью битового сокращения. Такое разделение получилось комбинированием всех поднаборов в подзадачах. Предполагаем, что числа хранятся в массиве &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B&amp;lt;/tex&amp;gt; так, что числа в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt; предшествуют числам в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{j}&amp;lt;/tex&amp;gt; если &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i &amp;lt; j&amp;lt;/tex&amp;gt; и &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;e_{i}&amp;lt;/tex&amp;gt; хранится после &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i - 1}&amp;lt;/tex&amp;gt;, но до &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;S_{i}&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[i]&amp;lt;/tex&amp;gt; находится в поднаборе &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[i].subset&amp;lt;/tex&amp;gt;. Чтобы позволить разделению выполниться, для каждого поднабора помещаем все &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[j]&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;B[j].subset&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На это потребуется линейное время и место.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим проблему упаковки, которая решается следующим образом. Считается, что число бит в контейнере &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log m \geqslant \log\log\log n&amp;lt;/tex&amp;gt;, потому что в противном случае можно использовать radix sort для сортировки чисел. У контейнера есть &amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n}&amp;lt;/tex&amp;gt; хешированных значений (сегментов) в себе на уровне &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log h&amp;lt;/tex&amp;gt; в ЭП-дереве. Полное число хешированных бит в контейнере равно &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;(2 \log n)(c \log\log n)&amp;lt;/tex&amp;gt; бит. Хешированные биты в контейнере выглядят как &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0^{i}t_{1}0^{i}t_{2} \ldots t&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{\frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{k}&amp;lt;/tex&amp;gt;-ые — хешированные биты, а нули {{---}} это просто нули. Сначала упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров в один и получаем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{1} = 0^{j}t_{1, 1}t_{2, 1} \ldots t_{\log\log n, 1}0^{j}t_{1, 2} \ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{  \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;, где &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{i, k}&amp;lt;/tex&amp;gt;: элемент с номером &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k = 1, 2,  \ldots, &amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{h}{\log\log n}&amp;lt;/tex&amp;gt; из &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;i&amp;lt;/tex&amp;gt;-ого контейнера. Используем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; шагов, чтобы упаковать &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{1}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{2} = 0&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;^{\frac{jh}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{1, 1}t_{2, 1} \ldots t_{\log\log n, 1}t_{1, 2}t_{2, 2} \ldots t_{1,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{2,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;. Теперь упакованные хеш-биты занимают &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;2 \log&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;\frac{n}{c}&amp;lt;/tex&amp;gt; бит. Используем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; времени чтобы распаковать &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{2}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{3, k} = 0&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;^{\frac{jh}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0^{r}t_{k, 1}0^{r}t_{k, 2} \ldots t_{k,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;k = 1, 2, \ldots, \log\log n&amp;lt;/tex&amp;gt;. Затем, используя &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; времени, упаковываем эти &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров в один &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{4} = 0^{r}t_{1, 1}0^{r}t_{1, 2} \ldots t_{1,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;0^{r}t_{2, 1} \ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;. Затем, используя &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; шагов, упаковываем &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{4}&amp;lt;/tex&amp;gt; в &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;w_{5} = 0^{s}t_{1, 1}t_{1, 2} \ldots t_{1,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;t_{2, 1}t_{2, 2} \ldots t_{\log\log n,}&amp;lt;/tex&amp;gt;&amp;lt;tex dpi=&amp;quot;150&amp;quot;&amp;gt;_{ \frac{h}{\log\log n}}&amp;lt;/tex&amp;gt;. В итоге используется &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\log\log n)&amp;lt;/tex&amp;gt; времени для упаковки &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;\log\log n&amp;lt;/tex&amp;gt; контейнеров. Считаем, что время, потраченное на один контейнер — константа.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Сортировка подсчетом]]&lt;br /&gt;
* [[Цифровая сортировка]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [http://www.sciencedirect.com/science/article/pii/S019667740300155X Deterministic Sorting in O(n log log n) Time and Linear Space. Yijie Han.]&lt;br /&gt;
* А. Андерссон. Fast deterministic sorting and searching in linear space. Proc. 1996 IEEE Symp. on Foundations of Computer Science. 135-141(1996)&lt;br /&gt;
* [http://dl.acm.org/citation.cfm?id=1236460 A. Andersson, M. Thorup. Dynamic ordered sets with exponential search trees.]&lt;br /&gt;
* [[wikipedia:en:Integer_sorting|Wikipedia {{---}} Integer sorting]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Сортировки]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Han-example.png&amp;diff=47948</id>
		<title>Файл:Han-example.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Han-example.png&amp;diff=47948"/>
				<updated>2015-06-07T09:16:43Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44387</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44387"/>
				<updated>2015-01-13T13:25:36Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 T[1..n] = 0&lt;br /&gt;
 '''for''' i = 1..n&lt;br /&gt;
   '''for''' j = 1..(i - 1)&lt;br /&gt;
     '''if''' P[j] &amp;gt; P[i]&lt;br /&gt;
       T[P[i]] = T[P[i]]++&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_merge'' {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_get'' {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' inverses_merge(ls1, ls2):&lt;br /&gt;
   result = []&lt;br /&gt;
   it1, it2 = ''null''&lt;br /&gt;
   '''while''' (it1 &amp;lt; ls1.length) '''and''' (it2 &amp;lt; ls2.length)&lt;br /&gt;
    '''if''' ls1[it1].item &amp;lt; ls2[it2].item&lt;br /&gt;
       result.append(ls1[it1])&lt;br /&gt;
       it1++&lt;br /&gt;
     '''else'''&lt;br /&gt;
       result.append(item = ls2[it2].item, inverses = ls2[it2].inverses + ls1.length - it1)&lt;br /&gt;
       it2++&lt;br /&gt;
   '''while''' it1 &amp;lt; ls1.length&lt;br /&gt;
     result.append(ls1[it1])&lt;br /&gt;
     it1++&lt;br /&gt;
   '''while''' it2 &amp;lt; ls2.length&lt;br /&gt;
     result.append(ls2[it2])&lt;br /&gt;
     it2++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
 &lt;br /&gt;
 '''def''' inverses_get(ls):&lt;br /&gt;
   '''if''' ls.length == 1&lt;br /&gt;
     '''return''' [(item = ls[0], inverses = 0)]&lt;br /&gt;
   '''else'''&lt;br /&gt;
     '''return''' inverses_merge(inverses_get(ls.first_half), inverses_get(ls.second_half))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''j'' {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''k'' {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''result'' {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover_straight(ls):&lt;br /&gt;
   n = ls.length&lt;br /&gt;
   result = array(0, n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k '''in''' ls&lt;br /&gt;
    j = 0&lt;br /&gt;
     '''for''' i = 0..(n - 1)&lt;br /&gt;
       '''if''' result[i] == 0&lt;br /&gt;
         '''if'''  j == k&lt;br /&gt;
           result[i] = curr&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           j++&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''build_segment_tree'' {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''node'' {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''node.index'' {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover(inv):&lt;br /&gt;
   n = inv.length&lt;br /&gt;
   tree = build_segment_tree(array(n, 1))&lt;br /&gt;
   result = array(n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k '''in''' inv&lt;br /&gt;
     node = tree.root&lt;br /&gt;
     '''while''' !node.is_leaf&lt;br /&gt;
       '''if''' k &amp;lt; node.left.value&lt;br /&gt;
         node = node.left&lt;br /&gt;
       '''else'''&lt;br /&gt;
         k -= node.left.value&lt;br /&gt;
         node = node.right&lt;br /&gt;
     result[node.index] = curr&lt;br /&gt;
     node.add(-1)&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3 {{---}} 29-31 с.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44386</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44386"/>
				<updated>2015-01-13T13:24:39Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 T[1..n] = 0&lt;br /&gt;
 '''for''' i = 1..n&lt;br /&gt;
   '''for''' j = 1..(i - 1)&lt;br /&gt;
     '''if''' P[j] &amp;gt; P[i]&lt;br /&gt;
       T[P[i]] = T[P[i]]++&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_merge'' {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_get'' {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' inverses_merge(ls1, ls2):&lt;br /&gt;
   result = []&lt;br /&gt;
   it1, it2 = ''null''&lt;br /&gt;
   '''while''' (it1 &amp;lt; ls1.length) '''and''' (it2 &amp;lt; ls2.length):&lt;br /&gt;
    '''if''' ls1[it1].item &amp;lt; ls2[it2].item&lt;br /&gt;
       result.append(ls1[it1])&lt;br /&gt;
       it1++&lt;br /&gt;
     '''else'''&lt;br /&gt;
       result.append(item = ls2[it2].item, inverses = ls2[it2].inverses + ls1.length - it1)&lt;br /&gt;
       it2++&lt;br /&gt;
   '''while''' it1 &amp;lt; ls1.length&lt;br /&gt;
     result.append(ls1[it1])&lt;br /&gt;
     it1++&lt;br /&gt;
   '''while''' it2 &amp;lt; ls2.length&lt;br /&gt;
     result.append(ls2[it2])&lt;br /&gt;
     it2++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
 &lt;br /&gt;
 '''def''' inverses_get(ls):&lt;br /&gt;
   '''if''' ls.length == 1&lt;br /&gt;
     '''return''' [(item = ls[0], inverses = 0)]&lt;br /&gt;
   '''else'''&lt;br /&gt;
     '''return''' inverses_merge(inverses_get(ls.first_half), inverses_get(ls.second_half))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''j'' {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''k'' {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''result'' {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover_straight(ls):&lt;br /&gt;
   n = ls.length&lt;br /&gt;
   result = array(0, n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k '''in''' ls&lt;br /&gt;
    j = 0&lt;br /&gt;
     '''for''' i = 0..(n - 1)&lt;br /&gt;
       '''if''' result[i] == 0&lt;br /&gt;
         '''if'''  j == k&lt;br /&gt;
           result[i] = curr&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           j++&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''build_segment_tree'' {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''node'' {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''node.index'' {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover(inv):&lt;br /&gt;
   n = inv.length&lt;br /&gt;
   tree = build_segment_tree(array(n, 1))&lt;br /&gt;
   result = array(n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k '''in''' inv&lt;br /&gt;
     node = tree.root&lt;br /&gt;
     '''while''' !node.is_leaf&lt;br /&gt;
       '''if''' k &amp;lt; node.left.value&lt;br /&gt;
         node = node.left&lt;br /&gt;
       '''else'''&lt;br /&gt;
         k -= node.left.value&lt;br /&gt;
         node = node.right&lt;br /&gt;
     result[node.index] = curr&lt;br /&gt;
     node.add(-1)&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3 {{---}} 29-31 с.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44384</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44384"/>
				<updated>2015-01-13T13:05:29Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 T[1..n] = 0&lt;br /&gt;
 '''for''' i = 1..n&lt;br /&gt;
   '''for''' j = 1..(i - 1)&lt;br /&gt;
     '''if''' P}[j] &amp;gt; P}[i]&lt;br /&gt;
       T[P[i]] = T[P[i]]++&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_merge'' {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_get'' {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' inverses_merge(ls1, ls2)}:&lt;br /&gt;
   result = []&lt;br /&gt;
   it1, it2 = ''null''&lt;br /&gt;
   '''while''' (it1 &amp;lt; ls1.length) '''and''' (it2 &amp;lt; ls2.length):&lt;br /&gt;
    '''if''' ls1[it1}].item &amp;lt; ls2[it2].item:&lt;br /&gt;
       result.append(ls1[it1])&lt;br /&gt;
       it1++&lt;br /&gt;
     '''else:'''&lt;br /&gt;
       result.append(item = ls2[it2].item, inverses = ls2[it2].inverses + ls1.length - it1)&lt;br /&gt;
       it2++&lt;br /&gt;
   '''while''' it1 &amp;lt; ls1.length):&lt;br /&gt;
     result.append(ls1[it1])&lt;br /&gt;
     it1++&lt;br /&gt;
   '''while''' (it2 &amp;lt; ls2.length):&lt;br /&gt;
     result.append(ls2[it2])&lt;br /&gt;
     it2++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
 &lt;br /&gt;
 '''def''' inverses_get(ls)}:&lt;br /&gt;
   '''if''' ls.length == 1&lt;br /&gt;
     '''return''' [(item = ls[0], inverses = 0)]&lt;br /&gt;
   '''else:'''&lt;br /&gt;
     '''return''' inverses_merge(inverses_get(ls.first_half), inverses_get(ls.second_half))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''j'' {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''k'' {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''result'' {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover_straight(ls):&lt;br /&gt;
   n = ls.length&lt;br /&gt;
   result = array(0, n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k ''in'' ls:&lt;br /&gt;
    j = 0&lt;br /&gt;
     '''for''' i..n&lt;br /&gt;
       '''if''' result[i] == 0&lt;br /&gt;
         '''if'''  j == k&lt;br /&gt;
           result[i] = curr&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           j++&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''build_segment_tree'' {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''node'' {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''node.index'' {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover(inv):&lt;br /&gt;
   n = inv.length&lt;br /&gt;
   tree = build_segment_tree(array(n, 1))&lt;br /&gt;
   result = array(n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k ''in'' inv&lt;br /&gt;
     node = tree.root&lt;br /&gt;
     '''while''' !node.is_leaf&lt;br /&gt;
       '''if''' k &amp;lt; node.left.value&lt;br /&gt;
         node = node.left&lt;br /&gt;
       '''else:'''&lt;br /&gt;
         k -= node.left.value&lt;br /&gt;
         node = node.right&lt;br /&gt;
     result[node.index] = curr&lt;br /&gt;
     node.add(-1)&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3 {{---}} 29-31 с.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44382</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44382"/>
				<updated>2015-01-13T04:39:20Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 T[1..n] = 0&lt;br /&gt;
 '''for''' i = 1..n&lt;br /&gt;
   '''for''' j = 1..(i - 1)&lt;br /&gt;
     '''if''' P}[j] &amp;gt; P}[i]&lt;br /&gt;
       T[P[i]] = T[P[i]]++&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_merge'' {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_get'' {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def'''  inverses_merge(ls1, ls2)}:&lt;br /&gt;
   result = []&lt;br /&gt;
   it1, it2 = ''null''&lt;br /&gt;
   '''while''' (it1 &amp;lt; ls1.length) '''and''' (it2 &amp;lt; ls2.length):&lt;br /&gt;
    '''if''' ls1[it1}].item &amp;lt; ls2[it2].item:&lt;br /&gt;
       result.append(ls1[it1])&lt;br /&gt;
       it1++&lt;br /&gt;
     '''else:'''&lt;br /&gt;
       result.append(item = ls2[it2].item, inverses = ls2[it2].inverses + ls1.length - it1)&lt;br /&gt;
       it2++&lt;br /&gt;
   '''while''' it1 &amp;lt; ls1.length):&lt;br /&gt;
     result.append(ls1[it1])&lt;br /&gt;
     it1++&lt;br /&gt;
   '''while''' (it2 &amp;lt; ls2.length):&lt;br /&gt;
     result.append(ls2[it2])&lt;br /&gt;
     it2++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
 &lt;br /&gt;
 '''def''' inverses_get(ls)}:&lt;br /&gt;
   '''if''' ls.length == 1&lt;br /&gt;
     '''return''' [(item = ls[0], inverses = 0)]&lt;br /&gt;
   '''else:'''&lt;br /&gt;
     '''return''' inverses_merge(inverses_get(ls.first_half), inverses_get(ls.second_half))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''j'' {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''k'' {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''result'' {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover_straight(ls):&lt;br /&gt;
   n = ls.length&lt;br /&gt;
   result = array(0, n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k ''in'' ls:&lt;br /&gt;
    j = 0&lt;br /&gt;
     '''for''' i..n&lt;br /&gt;
       '''if''' result[i] == 0&lt;br /&gt;
         '''if'''  j == k&lt;br /&gt;
           result[i] = curr&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           j++&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''build_segment_tree'' {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''node'' {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''node.index'' {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover(inv):&lt;br /&gt;
   n = inv.length&lt;br /&gt;
   tree = build_segment_tree(array(n, 1))&lt;br /&gt;
   result = array(n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k ''in'' inv&lt;br /&gt;
     node = tree.root&lt;br /&gt;
     '''while''' !node.is_leaf&lt;br /&gt;
       '''if''' k &amp;lt; node.left.value&lt;br /&gt;
         node = node.left&lt;br /&gt;
       '''else:'''&lt;br /&gt;
         k -= node.left.value&lt;br /&gt;
         node = node.right&lt;br /&gt;
     result[node.index] = curr&lt;br /&gt;
     node.add(-1)&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44381</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44381"/>
				<updated>2015-01-13T04:37:32Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 T[1..n] = 0&lt;br /&gt;
 '''for''' i = 1..n&lt;br /&gt;
   '''for''' j = 1..(i - 1)&lt;br /&gt;
     '''if''' P}[j] &amp;gt; P}[i]&lt;br /&gt;
       T[P[i]] = T[P[i]]++&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_merge'' {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''inverses_get'' {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def'''  inverses_merge(ls1, ls2)}:&lt;br /&gt;
   result = []&lt;br /&gt;
   it1, it2 = ''null''&lt;br /&gt;
   '''while''' (it1 &amp;lt; ls1.length) '''and''' (it2 &amp;lt; ls2.length):&lt;br /&gt;
    '''if''' ls1[it1}].item &amp;lt; ls2[it2].item:&lt;br /&gt;
       result.append(ls1[it1])&lt;br /&gt;
       it1++&lt;br /&gt;
     '''else:'''&lt;br /&gt;
       result.append(item = ls2[it2].item, inverses = ls2[it2].inverses + ls1.length - it1)&lt;br /&gt;
       it2++&lt;br /&gt;
   '''while''' it1 &amp;lt; ls1.length):&lt;br /&gt;
     result.append(ls1[it1])&lt;br /&gt;
     it1++&lt;br /&gt;
   '''while''' (it2 &amp;lt; ls2.length):&lt;br /&gt;
     result.append(ls2[it2])&lt;br /&gt;
     it2++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
 &lt;br /&gt;
 '''def''' inverses_get(ls)}:&lt;br /&gt;
   '''if''' ls.length == 1&lt;br /&gt;
     '''return''' [(item = ls[0], inverses = 0)]&lt;br /&gt;
   '''else:'''&lt;br /&gt;
     '''return''' inverses_merge(inverses_get(ls.first_half), inverses_get(ls.second_half))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''j'' {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''k'' {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''result'' {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover_straight(ls):&lt;br /&gt;
   n = ls.length&lt;br /&gt;
   result = array(0, n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k ''in'' ls:&lt;br /&gt;
    j = 0&lt;br /&gt;
     '''for''' i..n&lt;br /&gt;
       '''if''' result[i] == 0&lt;br /&gt;
         '''if'''  j == k&lt;br /&gt;
           result[i] = curr&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           j++&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''build_segment_tree'' {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;''node'' {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// ''node.index'' {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' recover(inv):&lt;br /&gt;
   n = inv.length&lt;br /&gt;
   tree = build_segment_tree(array(n, 1))&lt;br /&gt;
   result = array(n)&lt;br /&gt;
   curr = 1&lt;br /&gt;
   '''for''' k ''in'' inv&lt;br /&gt;
     node = tree.root&lt;br /&gt;
     '''while''' !node.is_leaf&lt;br /&gt;
       '''if''' k &amp;lt; node.left.value&lt;br /&gt;
         node = node.left&lt;br /&gt;
       '''else:'''&lt;br /&gt;
         k -= node.left.value&lt;br /&gt;
         node = node.right&lt;br /&gt;
     result[node.index] = curr&lt;br /&gt;
     node.add(-1)&lt;br /&gt;
     curr++&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44314</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44314"/>
				<updated>2015-01-12T16:08:02Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 &amp;lt;tex&amp;gt;\mathtt{T}[1..n]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;i\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..n&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;j\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..(i - 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt;\mathtt{P}[j]&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;gt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{P}[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]++&amp;lt;/tex&amp;gt;&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_merge&amp;lt;/tex&amp;gt; {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_get&amp;lt;/tex&amp;gt; {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def'''  &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(ls1, ls2)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = [  ]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;it\textit{1}, it\textit{2}\ =&amp;lt;/tex&amp;gt; ''null''&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length})&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''if''' &amp;lt;tex&amp;gt;\mathtt{ls1}[it\textit{1}]\mathtt{.item}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''else:'''&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(item\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}, inverses\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.inverses}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;-&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;it\textit{1})&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls2}[it\textit{2}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{inverses\_get(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''if''' &amp;lt;tex&amp;gt;\mathtt{ls.length}\ == 1:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;[(item = \mathtt{ls[0]}, inverses = 0)]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''else:'''&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(inverses\_get(ls.first\_half), inverses\_get(ls.second\_half))}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;result&amp;lt;/tex&amp;gt; {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover\_straight(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{ls.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(0, n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{ls}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;j\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;(i\ = 0, i &amp;lt; n, i++):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;\mathtt{result}[i]\ ==&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;0:&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' &amp;lt;tex&amp;gt;j\ ==&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;k:&amp;lt;/tex&amp;gt;&lt;br /&gt;
           &amp;lt;tex&amp;gt;\mathtt{result}[i]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           &amp;lt;tex&amp;gt;j++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;build\_segment\_tree&amp;lt;/tex&amp;gt; {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node&amp;lt;/tex&amp;gt; {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node.index&amp;lt;/tex&amp;gt; {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover(inv)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{inv.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{tree}\ = \mathtt{build\_segment\_tree}(\mathtt{array}(n, 1))&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{inv}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{tree.root}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''while''' &amp;lt;tex&amp;gt;(!\mathtt{node.is\_leaf}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;(k &amp;lt;\mathtt{node.left.value}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.left}&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''else:'''&lt;br /&gt;
         &amp;lt;tex&amp;gt;k\ -= \mathtt{node.left.value}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.right}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result}[\mathtt{node.index}]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node.add}(-1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44313</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44313"/>
				<updated>2015-01-12T16:05:13Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 &amp;lt;tex&amp;gt;\mathtt{T}[1..n]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;i\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..n&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;j\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..(i - 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt;\mathtt{P}[j]&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;gt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{P}[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]++&amp;lt;/tex&amp;gt;&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_merge&amp;lt;/tex&amp;gt; {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_get&amp;lt;/tex&amp;gt; {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def'''  &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(ls1, ls2)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = [  ]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;it\textit{1}, it\textit{2}\ =&amp;lt;/tex&amp;gt; ''null''&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length})&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''if''' &amp;lt;tex&amp;gt;\mathtt{ls1}[it\textit{1}]\mathtt{.item}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''else:'''&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(item\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}, inverses\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.inverses}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;-&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;it\textit{1})&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls2}[it\textit{2}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{inverses\_get(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''if''' &amp;lt;tex&amp;gt;\mathtt{ls.length}\ == 1:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;[(item = \mathtt{ls[0]}, inverses = 0)]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''else:'''&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(inverses\_get(ls.first\_half), inverses\_get(ls.second\_half))}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;result&amp;lt;/tex&amp;gt; {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover\_straight(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{ls.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(0, n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{ls}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;j\ = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;(i\ = 0, i &amp;lt; n, i++):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;\mathtt{result}[i]\ == 0:&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' &amp;lt;tex&amp;gt;j\ == k:&amp;lt;/tex&amp;gt;&lt;br /&gt;
           &amp;lt;tex&amp;gt;\mathtt{result}[i]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           &amp;lt;tex&amp;gt;j++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;build\_segment\_tree&amp;lt;/tex&amp;gt; {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node&amp;lt;/tex&amp;gt; {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node.index&amp;lt;/tex&amp;gt; {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover(inv)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{inv.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{tree}\ = \mathtt{build\_segment\_tree}(\mathtt{array}(n, 1))&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{inv}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{tree.root}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''while''' &amp;lt;tex&amp;gt;(!\mathtt{node.is\_leaf}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;(k &amp;lt;\mathtt{node.left.value}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.left}&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''else:'''&lt;br /&gt;
         &amp;lt;tex&amp;gt;k\ -= \mathtt{node.left.value}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.right}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result}[\mathtt{node.index}]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node.add}(-1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44312</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44312"/>
				<updated>2015-01-12T16:04:32Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 &amp;lt;tex&amp;gt;\mathtt{T}[1..n]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;i\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..n&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;j\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..(i - 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt;\mathtt{P}[j]&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;gt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{P}[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]++&amp;lt;/tex&amp;gt;&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_merge&amp;lt;/tex&amp;gt; {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_get&amp;lt;/tex&amp;gt; {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def'''  &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(ls1, ls2)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = [  ]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;it\textit{1}, it\textit{2}\ =&amp;lt;/tex&amp;gt; ''null''&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length})&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''if''' &amp;lt;tex&amp;gt;\mathtt{ls1}[it\textit{1}]\mathtt{.item}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''else:'''&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(item\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}, inverses\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.inverses}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;-&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;it\textit{1})&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls2}[it\textit{2}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{inverses\_get(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''if''' &amp;lt;tex&amp;gt;\mathtt{ls.length}\ == 1:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;[(item = \mathtt{ls[0]}, inverses = 0)]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''else:'''&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(inverses\_get(ls.first\_half), inverses\_get(ls.second\_half))}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;result&amp;lt;/tex&amp;gt; {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover\_straight(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{ls.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(0, n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{ls}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;j\ = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;(i\ = 0, i &amp;lt; n, i++):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;\mathtt{result}[i]\ == 0:&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' &amp;lt;tex&amp;gt;j\ == k:&amp;lt;/tex&amp;gt;&lt;br /&gt;
           &amp;lt;tex&amp;gt;\mathtt{result}[i]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           &amp;lt;tex&amp;gt;j++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;build\_segment\_tree&amp;lt;/tex&amp;gt; {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node&amp;lt;/tex&amp;gt; {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node.index&amp;lt;/tex&amp;gt; {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover(inv)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{inv.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{tree}\ = \mathtt{build\_segment\_tree}(\mathtt{array}(n, 1))&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{inv}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{tree.root}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''while''' &amp;lt;tex&amp;gt;(!\mathtt{node.is\_leaf}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;(k &amp;lt;\mathtt{node.left.value}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.left}&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''else:'''&lt;br /&gt;
         &amp;lt;tex&amp;gt;k\ -= \mathtt{node.left.value}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.right}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result}[\mathtt{node.index}]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node.add}(-1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44311</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44311"/>
				<updated>2015-01-12T16:04:00Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 &amp;lt;tex&amp;gt;\mathtt{T}[1..n]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;i\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..n&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;j\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..(i - 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt;\mathtt{P}[j]&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;gt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{P}[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]++&amp;lt;/tex&amp;gt;&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_merge&amp;lt;/tex&amp;gt; {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_get&amp;lt;/tex&amp;gt; {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def'''  &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(ls1, ls2)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = [  ]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;it\textit{1}, it\textit{2}\ =&amp;lt;/tex&amp;gt; ''null''&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length})&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''if''' &amp;lt;tex&amp;gt;\mathtt{ls1}[it\textit{1}]\mathtt{.item}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''else:'''&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(item\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}, inverses\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.inverses}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;-&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;it\textit{1})&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls2}[it\textit{2}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{inverses\_get(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''if''' &amp;lt;tex&amp;gt;\mathtt{ls.length}\ == 1:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;[(item = \mathtt{ls[0]}, inverses = 0)]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''else:'''&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(inverses\_get(ls.first\_half), inverses\_get(ls.second\_half))}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;result&amp;lt;/tex&amp;gt; {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover\_straight(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{ls.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(0, n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{ls}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;j\ = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;(i\ = 0, i &amp;lt; n, i++):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;\mathtt{result}[i]\ == 0:&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' &amp;lt;tex&amp;gt;j\ == k:&amp;lt;/tex&amp;gt;&lt;br /&gt;
           &amp;lt;tex&amp;gt;\mathtt{result}[i]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           &amp;lt;tex&amp;gt;j++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;build\_segment\_tre&amp;lt;/tex&amp;gt; {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node&amp;lt;/tex&amp;gt; {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node.index&amp;lt;/tex&amp;gt; {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover(inv)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{inv.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{tree}\ = \mathtt{build\_segment\_tree}(\mathtt{array}(n, 1))&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{inv}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{tree.root}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''while''' &amp;lt;tex&amp;gt;(!\mathtt{node.is\_leaf}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;(k &amp;lt;\mathtt{node.left.value}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.left}&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''else:'''&lt;br /&gt;
         &amp;lt;tex&amp;gt;k\ -= \mathtt{node.left.value}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.right}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result}[\mathtt{node.index}]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node.add}(-1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44310</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44310"/>
				<updated>2015-01-12T16:01:56Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 &amp;lt;tex&amp;gt;\mathtt{T}[1..n]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;i\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..n&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;j\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1..(i - 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''if''' &amp;lt;tex&amp;gt;\mathtt{P}[j]&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;gt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{P}[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{T}[\mathtt{P}[i]]++&amp;lt;/tex&amp;gt;&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_merge&amp;lt;/tex&amp;gt; {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_get&amp;lt;/tex&amp;gt; {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def'''  &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(ls1, ls2)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = [  ]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;it\textit{1}, it\textit{2}\ =&amp;lt;/tex&amp;gt; ''null''&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length})&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''if''' &amp;lt;tex&amp;gt;\mathtt{ls1}[it\textit{1}]\mathtt{.item}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''else:'''&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(item\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}, inverses\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.inverses}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;-&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;it\textit{1})&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls2}[it\textit{2}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{inverses\_get(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''if''' &amp;lt;tex&amp;gt;\mathtt{ls.length}\ == 1:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;[(item = \mathtt{ls[0]}, inverses = 0)]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''else:'''&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(inverses\_get(ls.first\_half), inverses\_get(ls.second\_half))}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;result&amp;lt;/tex&amp;gt; {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover\_straight(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{ls.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(0, n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{ls}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;j\ = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;(i\ = 0, i &amp;lt; n, i++):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;\mathtt{result}[i]\ == 0:&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' &amp;lt;tex&amp;gt;j\ == k:&amp;lt;/tex&amp;gt;&lt;br /&gt;
           &amp;lt;tex&amp;gt;\mathtt{result}[i]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           &amp;lt;tex&amp;gt;j++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;build_segment_tre&amp;lt;/tex&amp;gt; {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node&amp;lt;/tex&amp;gt; {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node.index&amp;lt;/tex&amp;gt; {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover(inv)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{inv.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{tree}\ = \mathtt{build\_segment\_tree}(\mathtt{array}(n, 1))&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{inv}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{tree.root}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''while''' &amp;lt;tex&amp;gt;(!\mathtt{node.is\_leaf}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;(k &amp;lt;\mathtt{node.left.value}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.left}&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''else:'''&lt;br /&gt;
         &amp;lt;tex&amp;gt;k\ -= \mathtt{node.left.value}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.right}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result}[\mathtt{node.index}]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node.add}(-1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&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;
&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44306</id>
		<title>Таблица инверсий</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B8%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B9&amp;diff=44306"/>
				<updated>2015-01-12T15:48:56Z</updated>
		
		<summary type="html">&lt;p&gt;6yry6e: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пусть &amp;lt;tex&amp;gt; P = (p_1,p_2,\dots,p_n)&amp;lt;/tex&amp;gt; является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел &amp;lt;tex&amp;gt; 1, 2,\dots, n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Инверсией''' (англ. ''inversion'') в перестановке &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; называется всякая пара индексов &amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;1\leqslant i&amp;lt;j\leqslant n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;P[i]&amp;gt;P[j]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
'''Таблицей инверсий''' (англ. ''inversion table'') перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; называют такую последовательность &amp;lt;tex&amp;gt; T = (t_1,t_2,\dots,t_n)&amp;lt;/tex&amp;gt;, в которой &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; равно числу элементов перестановки &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;, стоящих в &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; левее числа &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и больших &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;) ==&lt;br /&gt;
 &lt;br /&gt;
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него.&lt;br /&gt;
Алгоритм построения в псевдокоде выглядит так: &lt;br /&gt;
 T[1..n] = 0&lt;br /&gt;
 For i = 1..n&lt;br /&gt;
   For j = 1..(i - 1)&lt;br /&gt;
     if P[j] &amp;gt; P[i]&lt;br /&gt;
       T[P[i]] = T[P[i]] + 1&lt;br /&gt;
Сложность данного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. Уменьшить время работы можно используя алгоритм, похожий на [[Сортировка_слиянием |сортировку слиянием.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм построения за O(N log N) ==&lt;br /&gt;
&lt;br /&gt;
Пусть дано разбиение перестановки на два списка, причём для каждого элемента дано число инверсий слева с элементами того же списка и известно, что все числа первого списка стоят левее всех чисел второго списка в исходной перестановке. Будем считать количество инверсий слева элементов обоих списков следующим образом: сливаем списки, аналогично [[Сортировка_слиянием |сортировке слиянием.]]&lt;br /&gt;
&lt;br /&gt;
Если в результат нужно записать элемент первого списка, то все нерассмотренные элементы второго списка больше, следовательно, количество инверсий для этого элемента не меняется. Если в результат нужно записать элемент второго списка, то все нерассмотренные элементы первого списка больше его и стоят левее. Следовательно, количество инверсий для этого элемента следует увеличить на количество нерассмотренных элементов второго списка.&lt;br /&gt;
&lt;br /&gt;
Описанный алгоритм записывается в псевдокод следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_merge&amp;lt;/tex&amp;gt; {{---}} процедура, сливающая два списка пар&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;inverses\_get&amp;lt;/tex&amp;gt; {{---}} процедура, рекурсивно получающая таблицу инверсий для перестановки&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def'''  &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(ls1, ls2)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = [  ]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;it\textit{1}, it\textit{2}\ =&amp;lt;/tex&amp;gt; ''null''&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length})&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''if''' &amp;lt;tex&amp;gt;\mathtt{ls1}[it\textit{1}]\mathtt{.item}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''else:'''&lt;br /&gt;
       &amp;lt;tex&amp;gt;\mathtt{result.append}(item\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.item}, inverses\ =&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2}[it\textit{2}]\mathtt{.inverses}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;-&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;it\textit{1})&amp;lt;/tex&amp;gt;&lt;br /&gt;
       &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{1}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls1.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls1}[it\textit{1}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{1}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''while''' &amp;lt;tex&amp;gt;(it\textit{2}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;&amp;lt;&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathtt{ls2.length}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result.append}(\mathtt{ls2}[it\textit{2}])&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;it\textit{2}++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{inverses\_get(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''if''' &amp;lt;tex&amp;gt;\mathtt{ls.length}\ == 1:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;[(item = \mathtt{ls[0]}, inverses = 0)]&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''else:'''&lt;br /&gt;
     '''return''' &amp;lt;tex&amp;gt;\mathtt{inverses\_merge(inverses\_get(ls.first\_half), inverses\_get(ls.second\_half))}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сложность представленного алгоритма есть &amp;lt;tex&amp;gt;O(n\log n)&amp;lt;/tex&amp;gt;. Алгоритм с такой же сложностью можно построить с помощью [[Дерево_отрезков._Построение | дерева отрезков.]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритм восстановления ==&lt;br /&gt;
&lt;br /&gt;
Для восстановления перестановки по таблицы инверсий &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; воспользуемся следующим соображением: единица стоит в перестановке на &amp;lt;tex&amp;gt;T_0&amp;lt;/tex&amp;gt;-ом месте  (индексируем элементы с нуля), так как остальные числа в перестановке больше единицы. Далее, если известны расположения всех чисел &amp;lt;tex&amp;gt;1, \dots, k&amp;lt;/tex&amp;gt;, то число &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; стоит на &amp;lt;tex&amp;gt;T_{k + 1}&amp;lt;/tex&amp;gt;-ой ещё не занятой позиции: все числа, меньшие &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; уже расставлены. Это рассуждение напрямую переписывается в код следующим образом:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; {{---}} счётчик пропущенных свободных позиций&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; {{---}} количество инверсий слева для элемента curr&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;result&amp;lt;/tex&amp;gt; {{---}} массив, в который записывается перестановка. Равенство элемента массива нулю обозначает, что эта позиция свободна.&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover\_straight(ls)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{ls.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(0, n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{ls}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;j\ = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;(i\ = 0, i &amp;lt; n, i++):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;\mathtt{result}[i]\ == 0:&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''if''' &amp;lt;tex&amp;gt;j\ == k:&amp;lt;/tex&amp;gt;&lt;br /&gt;
           &amp;lt;tex&amp;gt;\mathtt{result}[i]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
           '''break'''&lt;br /&gt;
         '''else:'''&lt;br /&gt;
           &amp;lt;tex&amp;gt;j++&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот простой алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; — внутренний цикл делает до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций, внешний — ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Видно, что для восстановления нужно узнавать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию. Это можно делать с помощью [[Дерево_отрезков._Построение | дерева отрезков]] следующим образом: построим дерево отрезков для суммы на массиве из единиц. Единица в позиции означает, что данная позиция свободна. Чтобы найти &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ую свободную позицию, нужно спускаться (начиная с корня) в левое поддерево если сумма в нём больше, чем &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, и в правое дерево иначе.&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм переписывается в код следующим образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;build_segment_tre&amp;lt;/tex&amp;gt; {{---}} строит дерево отрезков над массивом&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node&amp;lt;/tex&amp;gt; {{---}} вершина дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;node.index&amp;lt;/tex&amp;gt; {{---}} индекс соответствующего элемента в массиве для листа дерева&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''def''' &amp;lt;tex&amp;gt;\mathtt{recover(inv)}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;n\ = \mathtt{inv.length}&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{tree}\ = \mathtt{build_segment_tree}(\mathtt{array}(n, 1))&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;\mathtt{result}\ = \mathtt{array}(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
   &amp;lt;tex&amp;gt;curr\ = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''for''' &amp;lt;tex&amp;gt;k \in \mathtt{inv}:&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{tree.root}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''while''' &amp;lt;tex&amp;gt;(!\mathtt{node.is\_leaf}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''if''' &amp;lt;tex&amp;gt;(k &amp;lt;\mathtt{node.left.value}):&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.left}&amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''else:'''&lt;br /&gt;
         &amp;lt;tex&amp;gt;k\ -= \mathtt{node.left.value}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;\mathtt{node}\ = \mathtt{node.right}&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{result}[\mathtt{node.index}]\ = curr&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;\mathtt{node.add}(-1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
     &amp;lt;tex&amp;gt;curr++&amp;lt;/tex&amp;gt;&lt;br /&gt;
   '''return''' &amp;lt;tex&amp;gt;\mathtt{result}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Этот алгоритм имеет сложность &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;: делается &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; итераций цикла, в которой происходит спуск по дереву высоты &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt; и один запрос на дереве отрезков. Таким образом, время работы алгоритма на каждой итерации есть &amp;lt;tex&amp;gt;O(\log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример построения таблицы инверсий и восстановления перестановки по таблице инверсий. Пусть дана перестановка &amp;lt;tex&amp;gt;(5, 7, 1, 3, 4, 6, 8, 2)&amp;lt;/tex&amp;gt;. Следующая таблица показывает работу алгоритма за &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;, на каждой строке один уровень рекурсии (на первой строке — самый глубокий). В скобках стоят пары: элемент перестановки, количество инверсий. Полужирным отмечены элементы, у которых обновилось значение количества инверсий на данном шаге.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: gray; text-align: center; padding : 0&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(5, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(7, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(1, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(3, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(4, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(6, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(8, 0)&lt;br /&gt;
| style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot; |(2, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 0), (3, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(4, 0), (6, 0)&lt;br /&gt;
|colspan = &amp;quot;2&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 1)''', (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(1, 2)''', '''(3, 2)''', (5, 0), (7, 0)&lt;br /&gt;
|colspan = &amp;quot;4&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|'''(2, 3)''', (4, 0), (6, 0), (8, 0)&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;8&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|(1, 2), '''(2, 6)''', (3, 2), '''(4, 2)''', (5, 0), '''(6, 1)''', (7, 0), (8, 0)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Полученная таблица инверсий: &amp;lt;tex&amp;gt;(2, 6, 2, 2, 0, 1, 0, 0)&amp;lt;/tex&amp;gt;. Восстановим перестановку по таблице инверсий, начиная с пустого массива.&lt;br /&gt;
&lt;br /&gt;
{| style = &amp;quot;border: 0px solid; background-color: grey; text-align: center; padding : 0;&amp;quot; cellspacing = &amp;quot;2&amp;quot;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем шесть свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{3}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем две свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{4}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиции и ставим &amp;lt;tex&amp;gt;\bf{5}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|пропускаем одну свободную позицию и ставим &amp;lt;tex&amp;gt;\bf{6}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{7}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: white; padding: 3px 6px&amp;quot;|&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|colspan = &amp;quot;1&amp;quot; style = &amp;quot;background-color: #EEF; text-align: left; padding: 3px 6px&amp;quot;|не пропускаем свободных позиций и ставим &amp;lt;tex&amp;gt;\bf{8}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Permutation Wikipedia {{---}} Permutation]&lt;br /&gt;
* Д. Кнут - Искусство программирования, том 3.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Матричное представление перестановок]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Комбинаторика ]]&lt;/div&gt;</summary>
		<author><name>6yry6e</name></author>	</entry>

	</feed>