<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.197.4.113&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.197.4.113&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/217.197.4.113"/>
		<updated>2026-05-19T16:38:19Z</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65340</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65340"/>
				<updated>2018-05-11T08:19:05Z</updated>
		
		<summary type="html">&lt;p&gt;217.197.4.113: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Фарака-Колтона, Бендера''' (англ. ''Farach-Colton, Bender'') — применяется для решения за &amp;lt;tex&amp;gt;\langle O(N),O(1) \rangle&amp;lt;/tex&amp;gt; времени специального случая задачи &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Может быть использован также для [[Сведение задачи LCA к задаче RMQ|решения задачи &amp;lt;tex&amp;gt;\mathrm{LCA}&amp;lt;/tex&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дан массив &amp;lt;tex&amp;gt;A[1 \ldots N]&amp;lt;/tex&amp;gt; целых чисел, соседние элементы которого отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Поступают онлайн запросы вида &amp;lt;tex&amp;gt;(l, r)&amp;lt;/tex&amp;gt;, для каждого из которых требуется найти минимум среди элементов &amp;lt;tex&amp;gt;A[l], A[l + 1], \ldots, A[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;\mathrm{RMQ}&amp;lt;/tex&amp;gt; с помощью [[Решение RMQ с помощью разреженной таблицы|разреженной таблицы]] за &amp;lt;tex&amp;gt;\langle O(N \log N),O(1) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность &amp;lt;tex&amp;gt;A_i&amp;lt;/tex&amp;gt; на блоки длины &amp;lt;tex&amp;gt;K=\dfrac{1}{2}\log_2 N&amp;lt;/tex&amp;gt;. Для каждого блока вычислим минимум на нём и определим &amp;lt;tex&amp;gt;B_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;
&lt;br /&gt;
На новой последовательности &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; построим [[Решение RMQ с помощью разреженной таблицы|разреженную таблицу]]. При этом размер разреженной таблицы и время её построения будут равны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\dfrac{N}{K}\log\dfrac{N}{K}=\bigg(\dfrac{2N}{\log N}\bigg)\log\bigg(\dfrac{2N}{\log N}\bigg)=\bigg(\dfrac{2N}{\log N}\bigg)\bigg(1+\log\bigg(\dfrac{N}{\log N}\bigg)\bigg)\leqslant \dfrac{2N}{\log N}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+2N=O(N)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь для ответа на запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;[l:r]&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;
* минимум на отрезке от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до конца блока, содержащего &amp;lt;tex&amp;gt;l&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;
* минимум от начала блока, содержащего &amp;lt;tex&amp;gt;r&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;
[[Файл:F-C_B_algo.png|500px|center|Части, из которых состоит ответ на запрос RMQ]]&lt;br /&gt;
&lt;br /&gt;
Второй элемент мы уже умеем находить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; с помощью &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; и разреженной таблицы. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.&lt;br /&gt;
&lt;br /&gt;
=== Минимум внутри блока ===&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=sameblocks&lt;br /&gt;
|statement=Если две последовательности &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y_i&amp;lt;/tex&amp;gt; таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. &amp;lt;tex&amp;gt;\forall k: x_k = y_k + C&amp;lt;/tex&amp;gt;), то любой запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; даст один и тот же ответ для обеих последовательностей.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, мы можем ''нормализовать'' блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=kindscount&lt;br /&gt;
|statement=Существует &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; различных типов нормализованных блоков.&lt;br /&gt;
|proof=Соседние элементы в блоках отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;-вектором длины &amp;lt;tex&amp;gt; \bigg(\dfrac{1}{2} \log_2 N\bigg) - 1&amp;lt;/tex&amp;gt;. Таких векторов &amp;lt;tex&amp;gt;2^{(\frac{1}{2} \log_2 N) - 1} = O(\sqrt N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Осталось создать &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; таблиц {{---}} по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, которых &amp;lt;tex&amp;gt;\bigg(\dfrac{1}{2}\log_2 N\bigg)^2 = O(\log^2 N)&amp;lt;/tex&amp;gt;. Для каждого блока в &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; необходимо заранее вычислить его тип. Для этого нужно подобрать некоторую функцию из множества блоков в множество натуральных чисел, не вызывающую коллизий. Например, вектор из нулей и единиц, соответствующий типу блока, можно записать в целочисленный тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, затратив на предподсчёт &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  '''function''' precalc(A: '''int[N]'''): &lt;br /&gt;
    block_size = log(N) / 2 &amp;lt;font color=green&amp;gt; // размеры блоков &amp;lt;/font&amp;gt;&lt;br /&gt;
    K = &amp;lt;tex&amp;gt;\lceil&amp;lt;/tex&amp;gt;N / block_size&amp;lt;tex&amp;gt;\rceil&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt; // количество блоков &amp;lt;/font&amp;gt; &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// предподсчитаем позиции минимумов в каждом блоке&amp;lt;/font&amp;gt;&lt;br /&gt;
    cur_block = -1&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      B[i] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' N - 1&lt;br /&gt;
      '''if''' i '''mod''' block_size == 0 &lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' B[cur_block] = -1 '''or''' A[B[cur_block]] &amp;gt; A[i]&lt;br /&gt;
        B[cur_block] = i&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// построим Sparse table на массиве B&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      ST[i][0] = B[i]&lt;br /&gt;
    '''for''' j = 1 '''to''' log(N)&lt;br /&gt;
      '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
        ind = (1 &amp;lt;&amp;lt; (j - 1)) + i&lt;br /&gt;
        '''if''' ind &amp;amp;ge; K&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
        '''else if''' A[ST[i][j - 1]] &amp;gt; A[ST[ind][j - 1]]&lt;br /&gt;
          ST[i][j] = ST[ind][j - 1] &lt;br /&gt;
        '''else'''&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Посчитаем тип для каждого блока&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      type[i] = 0 &lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0&lt;br /&gt;
    i = 0&lt;br /&gt;
    '''while''' i &amp;lt; N or j &amp;lt; K&lt;br /&gt;
     '''if''' j &amp;amp;ge; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' j &amp;gt; 0 '''and''' (i &amp;amp;ge; N '''or''' A[i - 1] &amp;lt; A[i])&lt;br /&gt;
        type[cur_block] += (1 &amp;lt;&amp;lt; (j - 1)) &lt;br /&gt;
      i++&lt;br /&gt;
      j++&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Осталось только для каждого блока предподсчитать позиции минимумов на всех подотрезках&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
        '''for''' r = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[i][l][r] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      t = type[i]&lt;br /&gt;
      '''if''' block_min[t][0][0] = -1 &amp;lt;font color=green&amp;gt;// если там записано, что-то отличное от -1, то значит, мы уже посчитали ответ для такого типа отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[t][l][l] = l&lt;br /&gt;
          '''for''' r = l + 1 '''to''' block_size - 1&lt;br /&gt;
            block_min[t][l][r] = block_min[t][l][r - 1]&lt;br /&gt;
            '''if''' i * block_size + r &amp;amp;le; N '''and''' A[i * block_size + block_min[t][l][r]] &amp;gt; A[i * block_size + r]&lt;br /&gt;
                block_min[t][l][r] = r&lt;br /&gt;
&lt;br /&gt;
  '''function''' block_RMQ(block_number: '''int''', l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    '''return''' block_min[type[block_number]][l][r] + block_number * block_size&lt;br /&gt;
&lt;br /&gt;
  '''function''' RMQ(l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    bl = l / block_size&lt;br /&gt;
    br = r / block_size&lt;br /&gt;
    '''if''' bl = br &amp;lt;font color=green&amp;gt;// если оба индекса внутри одного блока&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' A[block_RMQ(bl, l % block_size, r % block_size)]&lt;br /&gt;
    '''if''' bl + 1 &amp;lt; br &amp;lt;font color=green&amp;gt;// найдем минимум на блоках между крайними, если таковые есть&amp;lt;/font&amp;gt;&lt;br /&gt;
      power = log(br - bl - 1)&lt;br /&gt;
      ansb = min(A[ST[bl + 1][power]], A[ST[br - (1 &amp;lt;&amp;lt; power)][power]])&lt;br /&gt;
    ansl = A[block_RMQ(bl, l % block_size, block_size - 1)] &amp;lt;font color=green&amp;gt;// найдем минимум на отрезке от l до конца блока, содержащего l&amp;lt;/font&amp;gt;&lt;br /&gt;
    ansr = A[block_RMQ(bl, 0, r % block_size)] &amp;lt;font color=green&amp;gt;// найдем минимум от начала блока, содержащего r, до r &amp;lt;/font&amp;gt;   &lt;br /&gt;
    '''return''' min(ansb, min(ansl, ansr))&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Результат ===&lt;br /&gt;
Итого, на предподсчёт требуется &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени и памяти, а ответ на запрос вычисляется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Bender, M.A., Farach-Colton, M. {{---}} The LCA Problem Revisited. LATIN (2000), с. 88-94&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о наименьшем общем предке]]&lt;/div&gt;</summary>
		<author><name>217.197.4.113</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65292</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65292"/>
				<updated>2018-05-10T09:48:42Z</updated>
		
		<summary type="html">&lt;p&gt;217.197.4.113: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Фарака-Колтона, Бендера''' (англ. ''Farach-Colton, Bender'') — применяется для решения за &amp;lt;tex&amp;gt;\langle O(N),O(1) \rangle&amp;lt;/tex&amp;gt; времени специального случая задачи &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Может быть использован также для [[Сведение задачи LCA к задаче RMQ|решения задачи &amp;lt;tex&amp;gt;\mathrm{LCA}&amp;lt;/tex&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дан массив &amp;lt;tex&amp;gt;A[1 \ldots N]&amp;lt;/tex&amp;gt; целых чисел, соседние элементы которого отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Поступают онлайн запросы вида &amp;lt;tex&amp;gt;(l, r)&amp;lt;/tex&amp;gt;, для каждого из которых требуется найти минимум среди элементов &amp;lt;tex&amp;gt;A[l], A[l + 1], \ldots, A[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;\mathrm{RMQ}&amp;lt;/tex&amp;gt; с помощью [[Решение RMQ с помощью разреженной таблицы|разреженной таблицы]] за &amp;lt;tex&amp;gt;\langle O(N \log N),O(1) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность &amp;lt;tex&amp;gt;A_i&amp;lt;/tex&amp;gt; на блоки длины &amp;lt;tex&amp;gt;K=\dfrac{1}{2}\log_2 N&amp;lt;/tex&amp;gt;. Для каждого блока вычислим минимум на нём и определим &amp;lt;tex&amp;gt;B_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;
&lt;br /&gt;
На новой последовательности &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; построим [[Решение RMQ с помощью разреженной таблицы|разреженную таблицу]]. При этом размер разреженной таблицы и время её построения будут равны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\dfrac{N}{K}\log\dfrac{N}{K}=\bigg(\dfrac{2N}{\log N}\bigg)\log\bigg(\dfrac{2N}{\log N}\bigg)=\bigg(\dfrac{2N}{\log N}\bigg)\bigg(1+\log\bigg(\dfrac{N}{\log N}\bigg)\bigg)\leqslant \dfrac{2N}{\log N}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+2N=O(N)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь для ответа на запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;[l:r]&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;
* минимум на отрезке от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до конца блока, содержащего &amp;lt;tex&amp;gt;l&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;
* минимум от начала блока, содержащего &amp;lt;tex&amp;gt;r&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;
[[Файл:F-C_B_algo.png|500px|center|Части, из которых состоит ответ на запрос RMQ]]&lt;br /&gt;
&lt;br /&gt;
Второй элемент мы уже умеем находить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; с помощью &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; и разреженной таблицы. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.&lt;br /&gt;
&lt;br /&gt;
=== Минимум внутри блока ===&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=sameblocks&lt;br /&gt;
|statement=Если две последовательности &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y_i&amp;lt;/tex&amp;gt; таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. &amp;lt;tex&amp;gt;\forall k: x_k = y_k + C&amp;lt;/tex&amp;gt;), то любой запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; даст один и тот же ответ для обеих последовательностей.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, мы можем ''нормализовать'' блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=kindscount&lt;br /&gt;
|statement=Существует &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; различных типов нормализованных блоков.&lt;br /&gt;
|proof=Соседние элементы в блоках отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;-вектором длины &amp;lt;tex&amp;gt; \bigg(\dfrac{1}{2} \log_2 N\bigg) - 1&amp;lt;/tex&amp;gt;. Таких векторов &amp;lt;tex&amp;gt;2^{(\frac{1}{2} \log_2 N) - 1} = O(\sqrt N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Осталось создать &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; таблиц {{---}} по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, которых &amp;lt;tex&amp;gt;\bigg(\dfrac{1}{2}\log_2 N\bigg)^2 = O(\log^2 N)&amp;lt;/tex&amp;gt;. Для каждого блока в &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; необходимо заранее вычислить его тип. Для этого нужно подобрать некоторую функцию из множества блоков в множество натуральных чисел, не вызывающую коллизий. Например, вектор из нулей и единиц, соответствующий типу блока, можно записать в целочисленный тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, затратив на предподсчёт &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  '''function''' precalc(A: '''int[N]'''): &lt;br /&gt;
    block_size = log(N) / 2 &amp;lt;font color=green&amp;gt; // размеры блоков &amp;lt;/font&amp;gt;&lt;br /&gt;
    K = &amp;lt;tex&amp;gt;\lceil&amp;lt;/tex&amp;gt;N / block_size&amp;lt;tex&amp;gt;\rceil&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt; // количество блоков &amp;lt;/font&amp;gt; &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// предподсчитаем позиции минимумов в каждом блоке&amp;lt;/font&amp;gt;&lt;br /&gt;
    cur_block = -1&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      B[i] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' N - 1&lt;br /&gt;
      '''if''' i '''mod''' block_size == 0 &lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' B[cur_block] = -1 '''or''' A[B[cur_block]] &amp;gt; A[i]&lt;br /&gt;
        B[cur_block] = i&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// построим Sparse table на массиве B&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      ST[i][0] = B[i]&lt;br /&gt;
    '''for''' j = 1 '''to''' log(N)&lt;br /&gt;
      '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
        ind = (1 &amp;lt;&amp;lt; (j - 1)) + i&lt;br /&gt;
        '''if''' ind &amp;amp;ge; K&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
        '''else if''' A[ST[i][j - 1]] &amp;gt; A[ST[ind][j - 1]]&lt;br /&gt;
          ST[i][j] = ST[ind][j - 1] &lt;br /&gt;
        '''else'''&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Посчитаем тип для каждого блока&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      type[i] = 0 &lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0&lt;br /&gt;
    i = 0&lt;br /&gt;
    '''while''' i &amp;lt; N or j &amp;lt; K&lt;br /&gt;
     '''if''' j &amp;amp;ge; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' j &amp;gt; 0 '''and''' (i &amp;amp;ge; N '''or''' A[i - 1] &amp;lt; A[i])&lt;br /&gt;
        type[cur_block] += (1 &amp;lt;&amp;lt; (j - 1)) &lt;br /&gt;
      i++&lt;br /&gt;
      j++&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Осталось только для каждого блока предподсчитать позиции минимумов на всех подотрезках&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
        '''for''' r = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[i][l][r] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      t = type[i]&lt;br /&gt;
      '''if''' block_min[t][0][0] = -1 &amp;lt;font color=green&amp;gt;// если там записано, что-то отличное от -1, то значит, мы уже посчитали ответ для такого типа отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[t][l][l] = l&lt;br /&gt;
          '''for''' r = l + 1 '''to''' block_size - 1&lt;br /&gt;
            block_min[t][l][r] = block_min[t][l][r - 1]&lt;br /&gt;
            '''if''' i * block_size + r &amp;amp;le; N '''and''' A[i * block_size + block_min[t][l][r]] &amp;gt; A[i * block_size + r]&lt;br /&gt;
                block_min[t][l][r] = r&lt;br /&gt;
&lt;br /&gt;
  '''function''' block_RMQ(block_number: '''int''', l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    '''return''' block_min[type[block_number]][l][r] + block_number * block_size&lt;br /&gt;
&lt;br /&gt;
  '''function''' RMQ(l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    bl = l / block_size&lt;br /&gt;
    br = r / block_size&lt;br /&gt;
    '''if''' bl = br &amp;lt;font color=green&amp;gt;// если оба индекса внутри одного блока&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' A[block_RMQ(bl, l % block_size, r % block_size)]&lt;br /&gt;
    '''if''' bl + 1 &amp;lt; br &amp;lt;font color=green&amp;gt;// найдем минимум на блоках между крайними, если таковые есть&amp;lt;/font&amp;gt;&lt;br /&gt;
      power = log(br - bl + 1)&lt;br /&gt;
      ansb = min(A[ST[bl + 1][power]], A[ST[br - (1 &amp;lt;&amp;lt; power)][power]])&lt;br /&gt;
    ansl = A[block_RMQ(bl, l % block_size, block_size - 1)] &amp;lt;font color=green&amp;gt;// найдем минимум на отрезке от l до конца блока, содержащего l&amp;lt;/font&amp;gt;&lt;br /&gt;
    ansr = A[block_RMQ(bl, 0, r % block_size)] &amp;lt;font color=green&amp;gt;// найдем минимум от начала блока, содержащего r, до r &amp;lt;/font&amp;gt;   &lt;br /&gt;
    '''return''' min(ansb, min(ansl, ansr))&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Результат ===&lt;br /&gt;
Итого, на предподсчёт требуется &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени и памяти, а ответ на запрос вычисляется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Bender, M.A., Farach-Colton, M. {{---}} The LCA Problem Revisited. LATIN (2000), с. 88-94&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о наименьшем общем предке]]&lt;/div&gt;</summary>
		<author><name>217.197.4.113</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65291</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65291"/>
				<updated>2018-05-10T09:42:55Z</updated>
		
		<summary type="html">&lt;p&gt;217.197.4.113: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Фарака-Колтона, Бендера''' (англ. ''Farach-Colton, Bender'') — применяется для решения за &amp;lt;tex&amp;gt;\langle O(N),O(1) \rangle&amp;lt;/tex&amp;gt; времени специального случая задачи &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Может быть использован также для [[Сведение задачи LCA к задаче RMQ|решения задачи &amp;lt;tex&amp;gt;\mathrm{LCA}&amp;lt;/tex&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дан массив &amp;lt;tex&amp;gt;A[1 \ldots N]&amp;lt;/tex&amp;gt; целых чисел, соседние элементы которого отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Поступают онлайн запросы вида &amp;lt;tex&amp;gt;(l, r)&amp;lt;/tex&amp;gt;, для каждого из которых требуется найти минимум среди элементов &amp;lt;tex&amp;gt;A[l], A[l + 1], \ldots, A[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;\mathrm{RMQ}&amp;lt;/tex&amp;gt; с помощью [[Решение RMQ с помощью разреженной таблицы|разреженной таблицы]] за &amp;lt;tex&amp;gt;\langle O(N \log N),O(1) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность &amp;lt;tex&amp;gt;A_i&amp;lt;/tex&amp;gt; на блоки длины &amp;lt;tex&amp;gt;K=\dfrac{1}{2}\log_2 N&amp;lt;/tex&amp;gt;. Для каждого блока вычислим минимум на нём и определим &amp;lt;tex&amp;gt;B_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;
&lt;br /&gt;
На новой последовательности &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; построим [[Решение RMQ с помощью разреженной таблицы|разреженную таблицу]]. При этом размер разреженной таблицы и время её построения будут равны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\dfrac{N}{K}\log\dfrac{N}{K}=\bigg(\dfrac{2N}{\log N}\bigg)\log\bigg(\dfrac{2N}{\log N}\bigg)=\bigg(\dfrac{2N}{\log N}\bigg)\bigg(1+\log\bigg(\dfrac{N}{\log N}\bigg)\bigg)\leqslant \dfrac{2N}{\log N}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+2N=O(N)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь для ответа на запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;[l:r]&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;
* минимум на отрезке от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до конца блока, содержащего &amp;lt;tex&amp;gt;l&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;
* минимум от начала блока, содержащего &amp;lt;tex&amp;gt;r&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;
[[Файл:F-C_B_algo.png|500px|center|Части, из которых состоит ответ на запрос RMQ]]&lt;br /&gt;
&lt;br /&gt;
Второй элемент мы уже умеем находить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; с помощью &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; и разреженной таблицы. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.&lt;br /&gt;
&lt;br /&gt;
=== Минимум внутри блока ===&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=sameblocks&lt;br /&gt;
|statement=Если две последовательности &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y_i&amp;lt;/tex&amp;gt; таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. &amp;lt;tex&amp;gt;\forall k: x_k = y_k + C&amp;lt;/tex&amp;gt;), то любой запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; даст один и тот же ответ для обеих последовательностей.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, мы можем ''нормализовать'' блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=kindscount&lt;br /&gt;
|statement=Существует &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; различных типов нормализованных блоков.&lt;br /&gt;
|proof=Соседние элементы в блоках отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;-вектором длины &amp;lt;tex&amp;gt; \bigg(\dfrac{1}{2} \log_2 N\bigg) - 1&amp;lt;/tex&amp;gt;. Таких векторов &amp;lt;tex&amp;gt;2^{(\frac{1}{2} \log_2 N) - 1} = O(\sqrt N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Осталось создать &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; таблиц {{---}} по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, которых &amp;lt;tex&amp;gt;\bigg(\dfrac{1}{2}\log_2 N\bigg)^2 = O(\log^2 N)&amp;lt;/tex&amp;gt;. Для каждого блока в &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; необходимо заранее вычислить его тип. Для этого нужно подобрать некоторую функцию из множества блоков в множество натуральных чисел, не вызывающую коллизий. Например, вектор из нулей и единиц, соответствующий типу блока, можно записать в целочисленный тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, затратив на предподсчёт &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  '''function''' precalc(A: '''int[N]'''): &lt;br /&gt;
    block_size = log(N) / 2 &amp;lt;font color=green&amp;gt; // размеры блоков &amp;lt;/font&amp;gt;&lt;br /&gt;
    K = &amp;lt;tex&amp;gt;\lceil&amp;lt;/tex&amp;gt;N / block_size&amp;lt;tex&amp;gt;\rceil&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt; // количество блоков &amp;lt;/font&amp;gt; &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// предподсчитаем позиции минимумов в каждом блоке&amp;lt;/font&amp;gt;&lt;br /&gt;
    cur_block = -1&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      B[i] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' N - 1&lt;br /&gt;
      '''if''' i '''mod''' block_size == 0 &lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' B[cur_block] = -1 '''or''' A[B[cur_block]] &amp;gt; A[i]&lt;br /&gt;
        B[cur_block] = i&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// построим Sparse table на массиве B&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      ST[i][0] = B[i]&lt;br /&gt;
    '''for''' j = 1 '''to''' log(N)&lt;br /&gt;
      '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
        ind = (1 &amp;lt;&amp;lt; (j - 1)) + i&lt;br /&gt;
        '''if''' ind &amp;amp;ge; K&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
        '''else if''' A[ST[i][j - 1]] &amp;gt; A[ST[ind][j - 1]]&lt;br /&gt;
          ST[i][j] = ST[ind][j - 1] &lt;br /&gt;
        '''else'''&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Посчитаем тип для каждого блока&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      type[i] = 0 &lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0&lt;br /&gt;
    i = 0&lt;br /&gt;
    '''while''' i &amp;lt; N or j &amp;lt; K&lt;br /&gt;
     '''if''' j &amp;amp;ge; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' j &amp;gt; 0 '''and''' (i &amp;amp;ge; N '''or''' A[i - 1] &amp;lt; A[i])&lt;br /&gt;
        type[cur_block] += (1 &amp;lt;&amp;lt; (j - 1)) &lt;br /&gt;
      i++&lt;br /&gt;
      j++&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Осталось только для каждого блока предподсчитать позиции минимумов на всех подотрезках&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
        '''for''' r = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[i][l][r] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      t = type[i]&lt;br /&gt;
      '''if''' block_min[t][0][0] = -1 &amp;lt;font color=green&amp;gt;// если там записано, что-то отличное от -1, то значит, мы уже посчитали ответ для такого типа отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[t][l][l] = l&lt;br /&gt;
          '''for''' r = l + 1 '''to''' block_size - 1&lt;br /&gt;
            block_min[t][l][r] = block_min[t][l][r - 1]&lt;br /&gt;
            '''if''' i * block_size + r &amp;lt;tex&amp;gt;\leqslant &amp;lt;/tex&amp;gt; N '''and''' A[i * block_size + block_min[t][l][r]] &amp;gt; A[i * block_size + r]&lt;br /&gt;
                block_min[t][l][r] = r&lt;br /&gt;
&lt;br /&gt;
  '''function''' block_RMQ(block_number: '''int''', l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    '''return''' block_min[type[block_number]][l][r] + block_number * block_size&lt;br /&gt;
&lt;br /&gt;
  '''function''' RMQ(l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    bl = l / block_size&lt;br /&gt;
    br = r / block_size&lt;br /&gt;
    '''if''' bl = br &amp;lt;font color=green&amp;gt;// если оба индекса внутри одного блока&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' A[block_RMQ(bl, l % block_size, r % block_size)]&lt;br /&gt;
    '''if''' bl + 1 &amp;lt; br &amp;lt;font color=green&amp;gt;// найдем минимум на блоках между крайними, если таковые есть&amp;lt;/font&amp;gt;&lt;br /&gt;
      power = log(br - bl + 1)&lt;br /&gt;
      ansb = min(A[ST[bl + 1][power]], A[ST[br - (1 &amp;lt;&amp;lt; power)][power]])&lt;br /&gt;
    ansl = A[block_RMQ(bl, l % block_size, block_size - 1)] &amp;lt;font color=green&amp;gt;// найдем минимум на отрезке от l до конца блока, содержащего l&amp;lt;/font&amp;gt;&lt;br /&gt;
    ansr = A[block_RMQ(bl, 0, r % block_size)] &amp;lt;font color=green&amp;gt;// найдем минимум от начала блока, содержащего r, до r &amp;lt;/font&amp;gt;   &lt;br /&gt;
    '''return''' min(ansb, min(ansl, ansr))&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Результат ===&lt;br /&gt;
Итого, на предподсчёт требуется &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени и памяти, а ответ на запрос вычисляется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Bender, M.A., Farach-Colton, M. {{---}} The LCA Problem Revisited. LATIN (2000), с. 88-94&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о наименьшем общем предке]]&lt;/div&gt;</summary>
		<author><name>217.197.4.113</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65290</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65290"/>
				<updated>2018-05-10T09:41:33Z</updated>
		
		<summary type="html">&lt;p&gt;217.197.4.113: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Фарака-Колтона, Бендера''' (англ. ''Farach-Colton, Bender'') — применяется для решения за &amp;lt;tex&amp;gt;\langle O(N),O(1) \rangle&amp;lt;/tex&amp;gt; времени специального случая задачи &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Может быть использован также для [[Сведение задачи LCA к задаче RMQ|решения задачи &amp;lt;tex&amp;gt;\mathrm{LCA}&amp;lt;/tex&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дан массив &amp;lt;tex&amp;gt;A[1 \ldots N]&amp;lt;/tex&amp;gt; целых чисел, соседние элементы которого отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Поступают онлайн запросы вида &amp;lt;tex&amp;gt;(l, r)&amp;lt;/tex&amp;gt;, для каждого из которых требуется найти минимум среди элементов &amp;lt;tex&amp;gt;A[l], A[l + 1], \ldots, A[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;\mathrm{RMQ}&amp;lt;/tex&amp;gt; с помощью [[Решение RMQ с помощью разреженной таблицы|разреженной таблицы]] за &amp;lt;tex&amp;gt;\langle O(N \log N),O(1) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность &amp;lt;tex&amp;gt;A_i&amp;lt;/tex&amp;gt; на блоки длины &amp;lt;tex&amp;gt;K=\dfrac{1}{2}\log_2 N&amp;lt;/tex&amp;gt;. Для каждого блока вычислим минимум на нём и определим &amp;lt;tex&amp;gt;B_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;
&lt;br /&gt;
На новой последовательности &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; построим [[Решение RMQ с помощью разреженной таблицы|разреженную таблицу]]. При этом размер разреженной таблицы и время её построения будут равны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\dfrac{N}{K}\log\dfrac{N}{K}=\bigg(\dfrac{2N}{\log N}\bigg)\log\bigg(\dfrac{2N}{\log N}\bigg)=\bigg(\dfrac{2N}{\log N}\bigg)\bigg(1+\log\bigg(\dfrac{N}{\log N}\bigg)\bigg)\leqslant \dfrac{2N}{\log N}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+2N=O(N)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь для ответа на запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;[l:r]&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;
* минимум на отрезке от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до конца блока, содержащего &amp;lt;tex&amp;gt;l&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;
* минимум от начала блока, содержащего &amp;lt;tex&amp;gt;r&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;
[[Файл:F-C_B_algo.png|500px|center|Части, из которых состоит ответ на запрос RMQ]]&lt;br /&gt;
&lt;br /&gt;
Второй элемент мы уже умеем находить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; с помощью &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; и разреженной таблицы. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.&lt;br /&gt;
&lt;br /&gt;
=== Минимум внутри блока ===&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=sameblocks&lt;br /&gt;
|statement=Если две последовательности &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y_i&amp;lt;/tex&amp;gt; таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. &amp;lt;tex&amp;gt;\forall k: x_k = y_k + C&amp;lt;/tex&amp;gt;), то любой запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; даст один и тот же ответ для обеих последовательностей.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, мы можем ''нормализовать'' блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=kindscount&lt;br /&gt;
|statement=Существует &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; различных типов нормализованных блоков.&lt;br /&gt;
|proof=Соседние элементы в блоках отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;-вектором длины &amp;lt;tex&amp;gt; \bigg(\dfrac{1}{2} \log_2 N\bigg) - 1&amp;lt;/tex&amp;gt;. Таких векторов &amp;lt;tex&amp;gt;2^{(\frac{1}{2} \log_2 N) - 1} = O(\sqrt N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Осталось создать &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; таблиц {{---}} по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, которых &amp;lt;tex&amp;gt;\bigg(\dfrac{1}{2}\log_2 N\bigg)^2 = O(\log^2 N)&amp;lt;/tex&amp;gt;. Для каждого блока в &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; необходимо заранее вычислить его тип. Для этого нужно подобрать некоторую функцию из множества блоков в множество натуральных чисел, не вызывающую коллизий. Например, вектор из нулей и единиц, соответствующий типу блока, можно записать в целочисленный тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, затратив на предподсчёт &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  '''function''' precalc(A: '''int[N]'''): &lt;br /&gt;
    block_size = log(N) / 2 &amp;lt;font color=green&amp;gt; // размеры блоков &amp;lt;/font&amp;gt;&lt;br /&gt;
    K = &amp;lt;tex&amp;gt;\lceil&amp;lt;/tex&amp;gt;N / block_size&amp;lt;tex&amp;gt;\rceil&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt; // количество блоков &amp;lt;/font&amp;gt; &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// предподсчитаем позиции минимумов в каждом блоке&amp;lt;/font&amp;gt;&lt;br /&gt;
    cur_block = -1&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      B[i] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' N - 1&lt;br /&gt;
      '''if''' i '''mod''' block_size == 0 &lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' B[cur_block] = -1 '''or''' A[B[cur_block]] &amp;gt; A[i]&lt;br /&gt;
        B[cur_block] = i&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// построим Sparse table на массиве B&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      ST[i][0] = B[i]&lt;br /&gt;
    '''for''' j = 1 '''to''' log(N)&lt;br /&gt;
      '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
        ind = (1 &amp;lt;&amp;lt; (j - 1)) + i&lt;br /&gt;
        '''if''' ind &amp;amp;ge; K&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
        '''else if''' A[ST[i][j - 1]] &amp;gt; A[ST[ind][j - 1]]&lt;br /&gt;
          ST[i][j] = ST[ind][j - 1] &lt;br /&gt;
        '''else'''&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Посчитаем тип для каждого блока&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      type[i] = 0 &lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0&lt;br /&gt;
    i = 0&lt;br /&gt;
    '''while''' i &amp;lt; N or j &amp;lt; K&lt;br /&gt;
     '''if''' j &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' j &amp;gt; 0 '''and''' (i &amp;amp;ge; N '''or''' A[i - 1] &amp;lt; A[i])&lt;br /&gt;
        type[cur_block] += (1 &amp;lt;&amp;lt; (j - 1)) &lt;br /&gt;
      i++&lt;br /&gt;
      j++&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Осталось только для каждого блока предподсчитать позиции минимумов на всех подотрезках&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
        '''for''' r = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[i][l][r] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      t = type[i]&lt;br /&gt;
      '''if''' block_min[t][0][0] = -1 &amp;lt;font color=green&amp;gt;// если там записано, что-то отличное от -1, то значит, мы уже посчитали ответ для такого типа отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[t][l][l] = l&lt;br /&gt;
          '''for''' r = l + 1 '''to''' block_size - 1&lt;br /&gt;
            block_min[t][l][r] = block_min[t][l][r - 1]&lt;br /&gt;
            '''if''' i * block_size + r &amp;lt;tex&amp;gt;\leqslant &amp;lt;/tex&amp;gt; N '''and''' A[i * block_size + block_min[t][l][r]] &amp;gt; A[i * block_size + r]&lt;br /&gt;
                block_min[t][l][r] = r&lt;br /&gt;
&lt;br /&gt;
  '''function''' block_RMQ(block_number: '''int''', l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    '''return''' block_min[type[block_number]][l][r] + block_number * block_size&lt;br /&gt;
&lt;br /&gt;
  '''function''' RMQ(l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    bl = l / block_size&lt;br /&gt;
    br = r / block_size&lt;br /&gt;
    '''if''' bl = br &amp;lt;font color=green&amp;gt;// если оба индекса внутри одного блока&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' A[block_RMQ(bl, l % block_size, r % block_size)]&lt;br /&gt;
    '''if''' bl + 1 &amp;lt; br &amp;lt;font color=green&amp;gt;// найдем минимум на блоках между крайними, если таковые есть&amp;lt;/font&amp;gt;&lt;br /&gt;
      power = log(br - bl + 1)&lt;br /&gt;
      ansb = min(A[ST[bl + 1][power]], A[ST[br - (1 &amp;lt;&amp;lt; power)][power]])&lt;br /&gt;
    ansl = A[block_RMQ(bl, l % block_size, block_size - 1)] &amp;lt;font color=green&amp;gt;// найдем минимум на отрезке от l до конца блока, содержащего l&amp;lt;/font&amp;gt;&lt;br /&gt;
    ansr = A[block_RMQ(bl, 0, r % block_size)] &amp;lt;font color=green&amp;gt;// найдем минимум от начала блока, содержащего r, до r &amp;lt;/font&amp;gt;   &lt;br /&gt;
    '''return''' min(ansb, min(ansl, ansr))&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Результат ===&lt;br /&gt;
Итого, на предподсчёт требуется &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени и памяти, а ответ на запрос вычисляется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Bender, M.A., Farach-Colton, M. {{---}} The LCA Problem Revisited. LATIN (2000), с. 88-94&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о наименьшем общем предке]]&lt;/div&gt;</summary>
		<author><name>217.197.4.113</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65289</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65289"/>
				<updated>2018-05-10T09:34:19Z</updated>
		
		<summary type="html">&lt;p&gt;217.197.4.113: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Фарака-Колтона, Бендера''' (англ. ''Farach-Colton, Bender'') — применяется для решения за &amp;lt;tex&amp;gt;\langle O(N),O(1) \rangle&amp;lt;/tex&amp;gt; времени специального случая задачи &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Может быть использован также для [[Сведение задачи LCA к задаче RMQ|решения задачи &amp;lt;tex&amp;gt;\mathrm{LCA}&amp;lt;/tex&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дан массив &amp;lt;tex&amp;gt;A[1 \ldots N]&amp;lt;/tex&amp;gt; целых чисел, соседние элементы которого отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Поступают онлайн запросы вида &amp;lt;tex&amp;gt;(l, r)&amp;lt;/tex&amp;gt;, для каждого из которых требуется найти минимум среди элементов &amp;lt;tex&amp;gt;A[l], A[l + 1], \ldots, A[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;\mathrm{RMQ}&amp;lt;/tex&amp;gt; с помощью [[Решение RMQ с помощью разреженной таблицы|разреженной таблицы]] за &amp;lt;tex&amp;gt;\langle O(N \log N),O(1) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность &amp;lt;tex&amp;gt;A_i&amp;lt;/tex&amp;gt; на блоки длины &amp;lt;tex&amp;gt;K=\dfrac{1}{2}\log_2 N&amp;lt;/tex&amp;gt;. Для каждого блока вычислим минимум на нём и определим &amp;lt;tex&amp;gt;B_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;
&lt;br /&gt;
На новой последовательности &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; построим [[Решение RMQ с помощью разреженной таблицы|разреженную таблицу]]. При этом размер разреженной таблицы и время её построения будут равны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\dfrac{N}{K}\log\dfrac{N}{K}=\bigg(\dfrac{2N}{\log N}\bigg)\log\bigg(\dfrac{2N}{\log N}\bigg)=\bigg(\dfrac{2N}{\log N}\bigg)\bigg(1+\log\bigg(\dfrac{N}{\log N}\bigg)\bigg)\leqslant \dfrac{2N}{\log N}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+2N=O(N)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь для ответа на запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;[l:r]&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;
* минимум на отрезке от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до конца блока, содержащего &amp;lt;tex&amp;gt;l&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;
* минимум от начала блока, содержащего &amp;lt;tex&amp;gt;r&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;
[[Файл:F-C_B_algo.png|500px|center|Части, из которых состоит ответ на запрос RMQ]]&lt;br /&gt;
&lt;br /&gt;
Второй элемент мы уже умеем находить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; с помощью &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; и разреженной таблицы. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.&lt;br /&gt;
&lt;br /&gt;
=== Минимум внутри блока ===&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=sameblocks&lt;br /&gt;
|statement=Если две последовательности &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y_i&amp;lt;/tex&amp;gt; таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. &amp;lt;tex&amp;gt;\forall k: x_k = y_k + C&amp;lt;/tex&amp;gt;), то любой запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; даст один и тот же ответ для обеих последовательностей.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, мы можем ''нормализовать'' блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=kindscount&lt;br /&gt;
|statement=Существует &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; различных типов нормализованных блоков.&lt;br /&gt;
|proof=Соседние элементы в блоках отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;-вектором длины &amp;lt;tex&amp;gt; \bigg(\dfrac{1}{2} \log_2 N\bigg) - 1&amp;lt;/tex&amp;gt;. Таких векторов &amp;lt;tex&amp;gt;2^{(\frac{1}{2} \log_2 N) - 1} = O(\sqrt N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Осталось создать &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; таблиц {{---}} по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, которых &amp;lt;tex&amp;gt;\bigg(\dfrac{1}{2}\log_2 N\bigg)^2 = O(\log^2 N)&amp;lt;/tex&amp;gt;. Для каждого блока в &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; необходимо заранее вычислить его тип. Для этого нужно подобрать некоторую функцию из множества блоков в множество натуральных чисел, не вызывающую коллизий. Например, вектор из нулей и единиц, соответствующий типу блока, можно записать в целочисленный тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, затратив на предподсчёт &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  '''function''' precalc(A: '''int[N]'''): &lt;br /&gt;
    block_size = log(N) / 2 &amp;lt;font color=green&amp;gt; // размеры блоков &amp;lt;/font&amp;gt;&lt;br /&gt;
    K = &amp;lt;tex&amp;gt;\lceil&amp;lt;/tex&amp;gt;N / block_size&amp;lt;tex&amp;gt;\rceil&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt; // количество блоков &amp;lt;/font&amp;gt; &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// предподсчитаем позиции минимумов в каждом блоке&amp;lt;/font&amp;gt;&lt;br /&gt;
    cur_block = -1&lt;br /&gt;
    j = 0 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      B[i] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' N - 1&lt;br /&gt;
      '''if''' i '''mod''' block_size == 0 &lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' B[cur_block] = -1 '''or''' A[B[cur_block]] &amp;gt; A[i]&lt;br /&gt;
        B[cur_block] = i&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// построим Sparse table на массиве B&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      ST[i][0] = B[i]&lt;br /&gt;
    '''for''' j = 1 '''to''' log(N)&lt;br /&gt;
      '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
        ind = (1 &amp;lt;&amp;lt; (j - 1)) + i&lt;br /&gt;
        '''if''' ind &amp;lt;tex&amp;gt;\ge&amp;lt;/tex&amp;gt; K&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
        '''else if''' A[ST[i][j - 1]] &amp;gt; A[ST[ind][j - 1]]&lt;br /&gt;
          ST[i][j] = ST[ind][j - 1] &lt;br /&gt;
        '''else'''&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Посчитаем тип для каждого блока&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      type[i] = 0 &lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0&lt;br /&gt;
    i = 0&lt;br /&gt;
    '''while''' i &amp;lt; N or j &amp;lt; K&lt;br /&gt;
     '''if''' j &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' j &amp;gt; 0 '''and''' (i &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; N '''or''' A[i - 1] &amp;lt; A[i])&lt;br /&gt;
        type[cur_block] += (1 &amp;lt;&amp;lt; (j - 1)) &lt;br /&gt;
      i++&lt;br /&gt;
      j++&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Осталось только для каждого блока предподсчитать позиции минимумов на всех подотрезках&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
        '''for''' r = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[i][l][r] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      t = type[i]&lt;br /&gt;
      '''if''' block_min[t][0][0] = -1 &amp;lt;font color=green&amp;gt;// если там записано, что-то отличное от -1, то значит, мы уже посчитали ответ для такого типа отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[t][l][l] = l&lt;br /&gt;
          '''for''' r = l + 1 '''to''' block_size - 1&lt;br /&gt;
            block_min[t][l][r] = block_min[t][l][r - 1]&lt;br /&gt;
            '''if''' i * block_size + r &amp;lt;tex&amp;gt;\leqslant &amp;lt;/tex&amp;gt; N '''and''' A[i * block_size + block_min[t][l][r]] &amp;gt; A[i * block_size + r]&lt;br /&gt;
                block_min[t][l][r] = r&lt;br /&gt;
&lt;br /&gt;
  '''function''' block_RMQ(block_number: '''int''', l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    '''return''' block_min[type[block_number]][l][r] + block_number * block_size&lt;br /&gt;
&lt;br /&gt;
  '''function''' RMQ(l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    bl = l / block_size&lt;br /&gt;
    br = r / block_size&lt;br /&gt;
    '''if''' bl = br &amp;lt;font color=green&amp;gt;// если оба индекса внутри одного блока&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' A[block_RMQ(bl, l % block_size, r % block_size)]&lt;br /&gt;
    '''if''' bl + 1 &amp;lt; br &amp;lt;font color=green&amp;gt;// найдем минимум на блоках между крайними, если таковые есть&amp;lt;/font&amp;gt;&lt;br /&gt;
      power = log(br - bl + 1)&lt;br /&gt;
      ansb = min(A[ST[bl + 1][power]], A[ST[br - (1 &amp;lt;&amp;lt; power)][power]])&lt;br /&gt;
    ansl = A[block_RMQ(bl, l % block_size, block_size - 1)] &amp;lt;font color=green&amp;gt;// найдем минимум на отрезке от l до конца блока, содержащего l&amp;lt;/font&amp;gt;&lt;br /&gt;
    ansr = A[block_RMQ(bl, 0, r % block_size)] &amp;lt;font color=green&amp;gt;// найдем минимум от начала блока, содержащего r, до r &amp;lt;/font&amp;gt;   &lt;br /&gt;
    '''return''' min(ansb, min(ansl, ansr))&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Результат ===&lt;br /&gt;
Итого, на предподсчёт требуется &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени и памяти, а ответ на запрос вычисляется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Bender, M.A., Farach-Colton, M. {{---}} The LCA Problem Revisited. LATIN (2000), с. 88-94&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о наименьшем общем предке]]&lt;/div&gt;</summary>
		<author><name>217.197.4.113</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65288</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65288"/>
				<updated>2018-05-10T09:31:33Z</updated>
		
		<summary type="html">&lt;p&gt;217.197.4.113: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Фарака-Колтона, Бендера''' (англ. ''Farach-Colton, Bender'') — применяется для решения за &amp;lt;tex&amp;gt;\langle O(N),O(1) \rangle&amp;lt;/tex&amp;gt; времени специального случая задачи &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Может быть использован также для [[Сведение задачи LCA к задаче RMQ|решения задачи &amp;lt;tex&amp;gt;\mathrm{LCA}&amp;lt;/tex&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дан массив &amp;lt;tex&amp;gt;A[1 \ldots N]&amp;lt;/tex&amp;gt; целых чисел, соседние элементы которого отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Поступают онлайн запросы вида &amp;lt;tex&amp;gt;(l, r)&amp;lt;/tex&amp;gt;, для каждого из которых требуется найти минимум среди элементов &amp;lt;tex&amp;gt;A[l], A[l + 1], \ldots, A[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;\mathrm{RMQ}&amp;lt;/tex&amp;gt; с помощью [[Решение RMQ с помощью разреженной таблицы|разреженной таблицы]] за &amp;lt;tex&amp;gt;\langle O(N \log N),O(1) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность &amp;lt;tex&amp;gt;A_i&amp;lt;/tex&amp;gt; на блоки длины &amp;lt;tex&amp;gt;K=\dfrac{1}{2}\log_2 N&amp;lt;/tex&amp;gt;. Для каждого блока вычислим минимум на нём и определим &amp;lt;tex&amp;gt;B_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;
&lt;br /&gt;
На новой последовательности &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; построим [[Решение RMQ с помощью разреженной таблицы|разреженную таблицу]]. При этом размер разреженной таблицы и время её построения будут равны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\dfrac{N}{K}\log\dfrac{N}{K}=\bigg(\dfrac{2N}{\log N}\bigg)\log\bigg(\dfrac{2N}{\log N}\bigg)=\bigg(\dfrac{2N}{\log N}\bigg)\bigg(1+\log\bigg(\dfrac{N}{\log N}\bigg)\bigg)\leqslant \dfrac{2N}{\log N}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+2N=O(N)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь для ответа на запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;[l:r]&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;
* минимум на отрезке от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до конца блока, содержащего &amp;lt;tex&amp;gt;l&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;
* минимум от начала блока, содержащего &amp;lt;tex&amp;gt;r&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;
[[Файл:F-C_B_algo.png|500px|center|Части, из которых состоит ответ на запрос RMQ]]&lt;br /&gt;
&lt;br /&gt;
Второй элемент мы уже умеем находить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; с помощью &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; и разреженной таблицы. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.&lt;br /&gt;
&lt;br /&gt;
=== Минимум внутри блока ===&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=sameblocks&lt;br /&gt;
|statement=Если две последовательности &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y_i&amp;lt;/tex&amp;gt; таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. &amp;lt;tex&amp;gt;\forall k: x_k = y_k + C&amp;lt;/tex&amp;gt;), то любой запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; даст один и тот же ответ для обеих последовательностей.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, мы можем ''нормализовать'' блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=kindscount&lt;br /&gt;
|statement=Существует &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; различных типов нормализованных блоков.&lt;br /&gt;
|proof=Соседние элементы в блоках отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;-вектором длины &amp;lt;tex&amp;gt; \bigg(\dfrac{1}{2} \log_2 N\bigg) - 1&amp;lt;/tex&amp;gt;. Таких векторов &amp;lt;tex&amp;gt;2^{(\frac{1}{2} \log_2 N) - 1} = O(\sqrt N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Осталось создать &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; таблиц {{---}} по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, которых &amp;lt;tex&amp;gt;\bigg(\dfrac{1}{2}\log_2 N\bigg)^2 = O(\log^2 N)&amp;lt;/tex&amp;gt;. Для каждого блока в &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; необходимо заранее вычислить его тип. Для этого нужно подобрать некоторую функцию из множества блоков в множество натуральных чисел, не вызывающую коллизий. Например, вектор из нулей и единиц, соответствующий типу блока, можно записать в целочисленный тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, затратив на предподсчёт &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  '''function''' precalc(A: '''int[N]'''): &lt;br /&gt;
    block_size = log(N) / 2 &amp;lt;font color=green&amp;gt; // размеры блоков &amp;lt;/font&amp;gt;&lt;br /&gt;
    K = &amp;lt;tex&amp;gt;\lceil&amp;lt;/tex&amp;gt;N / block_size&amp;lt;tex&amp;gt;\rceil&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt; // количество блоков &amp;lt;/font&amp;gt; &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// предподсчитаем позиции минимумов в каждом блоке&amp;lt;/font&amp;gt;&lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      B[i] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' N - 1&lt;br /&gt;
      '''if''' i '''mod''' block_size == 0 &lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' B[cur_block] = -1 '''or''' A[B[cur_block]] &amp;gt; A[i]&lt;br /&gt;
        B[cur_block] = i&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// построим Sparse table на массиве B&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      ST[i][0] = B[i]&lt;br /&gt;
    '''for''' j = 1 '''to''' log(N)&lt;br /&gt;
      '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
        ind = (1 &amp;lt;&amp;lt; (j - 1)) + i&lt;br /&gt;
        '''if''' ind &amp;lt;tex&amp;gt;\geq&amp;lt;/tex&amp;gt; K&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
        '''else if''' A[ST[i][j - 1]] &amp;gt; A[ST[ind][j - 1]]&lt;br /&gt;
          ST[i][j] = ST[ind][j - 1] &lt;br /&gt;
        '''else'''&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Посчитаем тип для каждого блока&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      type[i] = 0 &lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0&lt;br /&gt;
    i = 0&lt;br /&gt;
    '''while''' i &amp;lt; N or j &amp;lt; K&lt;br /&gt;
     '''if''' j &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' j &amp;gt; 0 '''and''' (i &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; N '''or''' A[i - 1] &amp;lt; A[i])&lt;br /&gt;
        type[cur_block] += (1 &amp;lt;&amp;lt; (j - 1)) &lt;br /&gt;
      i++&lt;br /&gt;
      j++&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Осталось только для каждого блока предподсчитать позиции минимумов на всех подотрезках&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
        '''for''' r = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[i][l][r] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      t = type[i]&lt;br /&gt;
      '''if''' block_min[t][0][0] = -1 &amp;lt;font color=green&amp;gt;// если там записано, что-то отличное от -1, то значит, мы уже посчитали ответ для такого типа отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[t][l][l] = l&lt;br /&gt;
          '''for''' r = l + 1 '''to''' block_size - 1&lt;br /&gt;
            block_min[t][l][r] = block_min[t][l][r - 1]&lt;br /&gt;
            '''if''' i * block_size + r &amp;lt;tex&amp;gt;\leqslant &amp;lt;/tex&amp;gt; N '''and''' A[i * block_size + block_min[t][l][r]] &amp;gt; A[i * block_size + r]&lt;br /&gt;
                block_min[t][l][r] = r&lt;br /&gt;
&lt;br /&gt;
  '''function''' block_RMQ(block_number: '''int''', l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    '''return''' block_min[type[block_number]][l][r] + block_number * block_size&lt;br /&gt;
&lt;br /&gt;
  '''function''' RMQ(l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    bl = l / block_size&lt;br /&gt;
    br = r / block_size&lt;br /&gt;
    '''if''' bl = br &amp;lt;font color=green&amp;gt;// если оба индекса внутри одного блока&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' A[block_RMQ(bl, l % block_size, r % block_size)]&lt;br /&gt;
    '''if''' bl + 1 &amp;lt; br &amp;lt;font color=green&amp;gt;// найдем минимум на блоках между крайними, если таковые есть&amp;lt;/font&amp;gt;&lt;br /&gt;
      power = log(br - bl + 1)&lt;br /&gt;
      ansb = min(A[ST[bl + 1][power]], A[ST[br - (1 &amp;lt;&amp;lt; power)][power]])&lt;br /&gt;
    ansl = A[block_RMQ(bl, l % block_size, block_size - 1)] &amp;lt;font color=green&amp;gt;// найдем минимум на отрезке от l до конца блока, содержащего l&amp;lt;/font&amp;gt;&lt;br /&gt;
    ansr = A[block_RMQ(bl, 0, r % block_size)] &amp;lt;font color=green&amp;gt;// найдем минимум от начала блока, содержащего r, до r &amp;lt;/font&amp;gt;   &lt;br /&gt;
    '''return''' min(ansb, min(ansl, ansr))&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Результат ===&lt;br /&gt;
Итого, на предподсчёт требуется &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени и памяти, а ответ на запрос вычисляется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Bender, M.A., Farach-Colton, M. {{---}} The LCA Problem Revisited. LATIN (2000), с. 88-94&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о наименьшем общем предке]]&lt;/div&gt;</summary>
		<author><name>217.197.4.113</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65287</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65287"/>
				<updated>2018-05-10T09:27:23Z</updated>
		
		<summary type="html">&lt;p&gt;217.197.4.113: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Фарака-Колтона, Бендера''' (англ. ''Farach-Colton, Bender'') — применяется для решения за &amp;lt;tex&amp;gt;\langle O(N),O(1) \rangle&amp;lt;/tex&amp;gt; времени специального случая задачи &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Может быть использован также для [[Сведение задачи LCA к задаче RMQ|решения задачи &amp;lt;tex&amp;gt;\mathrm{LCA}&amp;lt;/tex&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дан массив &amp;lt;tex&amp;gt;A[1 \ldots N]&amp;lt;/tex&amp;gt; целых чисел, соседние элементы которого отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Поступают онлайн запросы вида &amp;lt;tex&amp;gt;(l, r)&amp;lt;/tex&amp;gt;, для каждого из которых требуется найти минимум среди элементов &amp;lt;tex&amp;gt;A[l], A[l + 1], \ldots, A[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;\mathrm{RMQ}&amp;lt;/tex&amp;gt; с помощью [[Решение RMQ с помощью разреженной таблицы|разреженной таблицы]] за &amp;lt;tex&amp;gt;\langle O(N \log N),O(1) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность &amp;lt;tex&amp;gt;A_i&amp;lt;/tex&amp;gt; на блоки длины &amp;lt;tex&amp;gt;K=\dfrac{1}{2}\log_2 N&amp;lt;/tex&amp;gt;. Для каждого блока вычислим минимум на нём и определим &amp;lt;tex&amp;gt;B_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;
&lt;br /&gt;
На новой последовательности &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; построим [[Решение RMQ с помощью разреженной таблицы|разреженную таблицу]]. При этом размер разреженной таблицы и время её построения будут равны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\dfrac{N}{K}\log\dfrac{N}{K}=\bigg(\dfrac{2N}{\log N}\bigg)\log\bigg(\dfrac{2N}{\log N}\bigg)=\bigg(\dfrac{2N}{\log N}\bigg)\bigg(1+\log\bigg(\dfrac{N}{\log N}\bigg)\bigg)\leqslant \dfrac{2N}{\log N}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+2N=O(N)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь для ответа на запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;[l:r]&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;
* минимум на отрезке от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до конца блока, содержащего &amp;lt;tex&amp;gt;l&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;
* минимум от начала блока, содержащего &amp;lt;tex&amp;gt;r&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;
[[Файл:F-C_B_algo.png|500px|center|Части, из которых состоит ответ на запрос RMQ]]&lt;br /&gt;
&lt;br /&gt;
Второй элемент мы уже умеем находить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; с помощью &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; и разреженной таблицы. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.&lt;br /&gt;
&lt;br /&gt;
=== Минимум внутри блока ===&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=sameblocks&lt;br /&gt;
|statement=Если две последовательности &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y_i&amp;lt;/tex&amp;gt; таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. &amp;lt;tex&amp;gt;\forall k: x_k = y_k + C&amp;lt;/tex&amp;gt;), то любой запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; даст один и тот же ответ для обеих последовательностей.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, мы можем ''нормализовать'' блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=kindscount&lt;br /&gt;
|statement=Существует &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; различных типов нормализованных блоков.&lt;br /&gt;
|proof=Соседние элементы в блоках отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;-вектором длины &amp;lt;tex&amp;gt; \bigg(\dfrac{1}{2} \log_2 N\bigg) - 1&amp;lt;/tex&amp;gt;. Таких векторов &amp;lt;tex&amp;gt;2^{(\frac{1}{2} \log_2 N) - 1} = O(\sqrt N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Осталось создать &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; таблиц {{---}} по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, которых &amp;lt;tex&amp;gt;\bigg(\dfrac{1}{2}\log_2 N\bigg)^2 = O(\log^2 N)&amp;lt;/tex&amp;gt;. Для каждого блока в &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; необходимо заранее вычислить его тип. Для этого нужно подобрать некоторую функцию из множества блоков в множество натуральных чисел, не вызывающую коллизий. Например, вектор из нулей и единиц, соответствующий типу блока, можно записать в целочисленный тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, затратив на предподсчёт &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  '''function''' precalc(A: '''int[N]'''): &lt;br /&gt;
    block_size = log(N) / 2 &amp;lt;font color=green&amp;gt; // размеры блоков &amp;lt;/font&amp;gt;&lt;br /&gt;
    K = &amp;lt;tex&amp;gt;\lceil&amp;lt;/tex&amp;gt;N / block_size&amp;lt;tex&amp;gt;\rceil&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt; // количество блоков &amp;lt;/font&amp;gt; &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// предподсчитаем позиции минимумов в каждом блоке&amp;lt;/font&amp;gt;&lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      B[i] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' N - 1&lt;br /&gt;
      '''if''' j &amp;lt;tex&amp;gt;\ge&amp;lt;/tex&amp;gt; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' B[cur_block] = -1 '''or''' A[B[cur_block]] &amp;gt; A[i]&lt;br /&gt;
        B[cur_block] = i&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// построим Sparse table на массиве B&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      ST[i][0] = B[i]&lt;br /&gt;
    '''for''' j = 1 '''to''' log(N)&lt;br /&gt;
      '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
        ind = (1 &amp;lt;&amp;lt; (j - 1)) + i&lt;br /&gt;
        '''if''' ind &amp;lt;tex&amp;gt;\geq&amp;lt;/tex&amp;gt; K&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
        '''else if''' A[ST[i][j - 1]] &amp;gt; A[ST[ind][j - 1]]&lt;br /&gt;
          ST[i][j] = ST[ind][j - 1] &lt;br /&gt;
        '''else'''&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Посчитаем тип для каждого блока&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      type[i] = 0 &lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0&lt;br /&gt;
    i = 0&lt;br /&gt;
    '''while''' i &amp;lt; N or j &amp;lt; K&lt;br /&gt;
     '''if''' j &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' j &amp;gt; 0 '''and''' (i &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; N '''or''' A[i - 1] &amp;lt; A[i])&lt;br /&gt;
        type[cur_block] += (1 &amp;lt;&amp;lt; (j - 1)) &lt;br /&gt;
      i++&lt;br /&gt;
      j++&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Осталось только для каждого блока предподсчитать позиции минимумов на всех подотрезках&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
        '''for''' r = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[i][l][r] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      t = type[i]&lt;br /&gt;
      '''if''' block_min[t][0][0] = -1 &amp;lt;font color=green&amp;gt;// если там записано, что-то отличное от -1, то значит, мы уже посчитали ответ для такого типа отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[t][l][l] = l&lt;br /&gt;
          '''for''' r = l + 1 '''to''' block_size - 1&lt;br /&gt;
            block_min[t][l][r] = block_min[t][l][r - 1]&lt;br /&gt;
            '''if''' i * block_size + r &amp;lt;tex&amp;gt;\leqslant &amp;lt;/tex&amp;gt; N '''and''' A[i * block_size + block_min[t][l][r]] &amp;gt; A[i * block_size + r]&lt;br /&gt;
                block_min[t][l][r] = r&lt;br /&gt;
&lt;br /&gt;
  '''function''' block_RMQ(block_number: '''int''', l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    '''return''' block_min[type[block_number]][l][r] + block_number * block_size&lt;br /&gt;
&lt;br /&gt;
  '''function''' RMQ(l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    bl = l / block_size&lt;br /&gt;
    br = r / block_size&lt;br /&gt;
    '''if''' bl = br &amp;lt;font color=green&amp;gt;// если оба индекса внутри одного блока&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' A[block_RMQ(bl, l % block_size, r % block_size)]&lt;br /&gt;
    '''if''' bl + 1 &amp;lt; br &amp;lt;font color=green&amp;gt;// найдем минимум на блоках между крайними, если таковые есть&amp;lt;/font&amp;gt;&lt;br /&gt;
      power = log(br - bl + 1)&lt;br /&gt;
      ansb = min(A[ST[bl + 1][power]], A[ST[br - (1 &amp;lt;&amp;lt; power)][power]])&lt;br /&gt;
    ansl = A[block_RMQ(bl, l % block_size, block_size - 1)] &amp;lt;font color=green&amp;gt;// найдем минимум на отрезке от l до конца блока, содержащего l&amp;lt;/font&amp;gt;&lt;br /&gt;
    ansr = A[block_RMQ(bl, 0, r % block_size)] &amp;lt;font color=green&amp;gt;// найдем минимум от начала блока, содержащего r, до r &amp;lt;/font&amp;gt;   &lt;br /&gt;
    '''return''' min(ansb, min(ansl, ansr))&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Результат ===&lt;br /&gt;
Итого, на предподсчёт требуется &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени и памяти, а ответ на запрос вычисляется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Bender, M.A., Farach-Colton, M. {{---}} The LCA Problem Revisited. LATIN (2000), с. 88-94&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о наименьшем общем предке]]&lt;/div&gt;</summary>
		<author><name>217.197.4.113</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65286</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65286"/>
				<updated>2018-05-10T09:22:50Z</updated>
		
		<summary type="html">&lt;p&gt;217.197.4.113: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Фарака-Колтона, Бендера''' (англ. ''Farach-Colton, Bender'') — применяется для решения за &amp;lt;tex&amp;gt;\langle O(N),O(1) \rangle&amp;lt;/tex&amp;gt; времени специального случая задачи &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Может быть использован также для [[Сведение задачи LCA к задаче RMQ|решения задачи &amp;lt;tex&amp;gt;\mathrm{LCA}&amp;lt;/tex&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дан массив &amp;lt;tex&amp;gt;A[1 \ldots N]&amp;lt;/tex&amp;gt; целых чисел, соседние элементы которого отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Поступают онлайн запросы вида &amp;lt;tex&amp;gt;(l, r)&amp;lt;/tex&amp;gt;, для каждого из которых требуется найти минимум среди элементов &amp;lt;tex&amp;gt;A[l], A[l + 1], \ldots, A[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;\mathrm{RMQ}&amp;lt;/tex&amp;gt; с помощью [[Решение RMQ с помощью разреженной таблицы|разреженной таблицы]] за &amp;lt;tex&amp;gt;\langle O(N \log N),O(1) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность &amp;lt;tex&amp;gt;A_i&amp;lt;/tex&amp;gt; на блоки длины &amp;lt;tex&amp;gt;K=\dfrac{1}{2}\log_2 N&amp;lt;/tex&amp;gt;. Для каждого блока вычислим минимум на нём и определим &amp;lt;tex&amp;gt;B_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;
&lt;br /&gt;
На новой последовательности &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; построим [[Решение RMQ с помощью разреженной таблицы|разреженную таблицу]]. При этом размер разреженной таблицы и время её построения будут равны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\dfrac{N}{K}\log\dfrac{N}{K}=\bigg(\dfrac{2N}{\log N}\bigg)\log\bigg(\dfrac{2N}{\log N}\bigg)=\bigg(\dfrac{2N}{\log N}\bigg)\bigg(1+\log\bigg(\dfrac{N}{\log N}\bigg)\bigg)\leqslant \dfrac{2N}{\log N}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+2N=O(N)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь для ответа на запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;[l:r]&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;
* минимум на отрезке от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до конца блока, содержащего &amp;lt;tex&amp;gt;l&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;
* минимум от начала блока, содержащего &amp;lt;tex&amp;gt;r&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;
[[Файл:F-C_B_algo.png|500px|center|Части, из которых состоит ответ на запрос RMQ]]&lt;br /&gt;
&lt;br /&gt;
Второй элемент мы уже умеем находить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; с помощью &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; и разреженной таблицы. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.&lt;br /&gt;
&lt;br /&gt;
=== Минимум внутри блока ===&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=sameblocks&lt;br /&gt;
|statement=Если две последовательности &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y_i&amp;lt;/tex&amp;gt; таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. &amp;lt;tex&amp;gt;\forall k: x_k = y_k + C&amp;lt;/tex&amp;gt;), то любой запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; даст один и тот же ответ для обеих последовательностей.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, мы можем ''нормализовать'' блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=kindscount&lt;br /&gt;
|statement=Существует &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; различных типов нормализованных блоков.&lt;br /&gt;
|proof=Соседние элементы в блоках отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;-вектором длины &amp;lt;tex&amp;gt; \bigg(\dfrac{1}{2} \log_2 N\bigg) - 1&amp;lt;/tex&amp;gt;. Таких векторов &amp;lt;tex&amp;gt;2^{(\frac{1}{2} \log_2 N) - 1} = O(\sqrt N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Осталось создать &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; таблиц {{---}} по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, которых &amp;lt;tex&amp;gt;\bigg(\dfrac{1}{2}\log_2 N\bigg)^2 = O(\log^2 N)&amp;lt;/tex&amp;gt;. Для каждого блока в &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; необходимо заранее вычислить его тип. Для этого нужно подобрать некоторую функцию из множества блоков в множество натуральных чисел, не вызывающую коллизий. Например, вектор из нулей и единиц, соответствующий типу блока, можно записать в целочисленный тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, затратив на предподсчёт &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  '''function''' precalc(A: '''int[N]'''): &lt;br /&gt;
    block_size = log(N) / 2 &amp;lt;font color=green&amp;gt; // размеры блоков &amp;lt;/font&amp;gt;&lt;br /&gt;
    K = &amp;lt;tex&amp;gt;\lceil&amp;lt;/tex&amp;gt;N / block_size&amp;lt;tex&amp;gt;\rceil&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt; // количество блоков &amp;lt;/font&amp;gt; &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// предподсчитаем позиции минимумов в каждом блоке&amp;lt;/font&amp;gt;&lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      B[i] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' N - 1&lt;br /&gt;
      '''if''' j &amp;lt;tex&amp;gt;\geq&amp;lt;/tex&amp;gt; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' B[cur_block] = -1 '''or''' A[B[cur_block]] &amp;gt; A[i]&lt;br /&gt;
        B[cur_block] = i&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// построим Sparse table на массиве B&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      ST[i][0] = B[i]&lt;br /&gt;
    '''for''' j = 1 '''to''' log(N)&lt;br /&gt;
      '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
        ind = (1 &amp;lt;&amp;lt; (j - 1)) + i&lt;br /&gt;
        '''if''' ind &amp;lt;tex&amp;gt;\geq&amp;lt;/tex&amp;gt; K&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
        '''else if''' A[ST[i][j - 1]] &amp;gt; A[ST[ind][j - 1]]&lt;br /&gt;
          ST[i][j] = ST[ind][j - 1] &lt;br /&gt;
        '''else'''&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Посчитаем тип для каждого блока&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      type[i] = 0 &lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0&lt;br /&gt;
    i = 0&lt;br /&gt;
    '''while''' i &amp;lt; N or j &amp;lt; K&lt;br /&gt;
     '''if''' j &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' j &amp;gt; 0 '''and''' (i &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; N '''or''' A[i - 1] &amp;lt; A[i])&lt;br /&gt;
        type[cur_block] += (1 &amp;lt;&amp;lt; (j - 1)) &lt;br /&gt;
      i++&lt;br /&gt;
      j++&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Осталось только для каждого блока предподсчитать позиции минимумов на всех подотрезках&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
        '''for''' r = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[i][l][r] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      t = type[i]&lt;br /&gt;
      '''if''' block_min[t][0][0] = -1 &amp;lt;font color=green&amp;gt;// если там записано, что-то отличное от -1, то значит, мы уже посчитали ответ для такого типа отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[t][l][l] = l&lt;br /&gt;
          '''for''' r = l + 1 '''to''' block_size - 1&lt;br /&gt;
            block_min[t][l][r] = block_min[t][l][r - 1]&lt;br /&gt;
            '''if''' i * block_size + r &amp;lt;tex&amp;gt;\leqslant &amp;lt;/tex&amp;gt; N '''and''' A[i * block_size + block_min[t][l][r]] &amp;gt; A[i * block_size + r]&lt;br /&gt;
                block_min[t][l][r] = r&lt;br /&gt;
&lt;br /&gt;
  '''function''' block_RMQ(block_number: '''int''', l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    '''return''' block_min[type[block_number]][l][r] + block_number * block_size&lt;br /&gt;
&lt;br /&gt;
  '''function''' RMQ(l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    bl = l / block_size&lt;br /&gt;
    br = r / block_size&lt;br /&gt;
    '''if''' bl = br &amp;lt;font color=green&amp;gt;// если оба индекса внутри одного блока&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' A[block_RMQ(bl, l % block_size, r % block_size)]&lt;br /&gt;
    '''if''' bl + 1 &amp;lt; br &amp;lt;font color=green&amp;gt;// найдем минимум на блоках между крайними, если таковые есть&amp;lt;/font&amp;gt;&lt;br /&gt;
      power = log(br - bl + 1)&lt;br /&gt;
      ansb = min(A[ST[bl + 1][power]], A[ST[br - (1 &amp;lt;&amp;lt; power)][power]])&lt;br /&gt;
    ansl = A[block_RMQ(bl, l % block_size, block_size - 1)] &amp;lt;font color=green&amp;gt;// найдем минимум на отрезке от l до конца блока, содержащего l&amp;lt;/font&amp;gt;&lt;br /&gt;
    ansr = A[block_RMQ(bl, 0, r % block_size)] &amp;lt;font color=green&amp;gt;// найдем минимум от начала блока, содержащего r, до r &amp;lt;/font&amp;gt;   &lt;br /&gt;
    '''return''' min(ansb, min(ansl, ansr))&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Результат ===&lt;br /&gt;
Итого, на предподсчёт требуется &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени и памяти, а ответ на запрос вычисляется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Bender, M.A., Farach-Colton, M. {{---}} The LCA Problem Revisited. LATIN (2000), с. 88-94&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о наименьшем общем предке]]&lt;/div&gt;</summary>
		<author><name>217.197.4.113</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65285</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%A4%D0%B0%D1%80%D0%B0%D0%BA%D0%B0-%D0%9A%D0%BE%D0%BB%D1%82%D0%BE%D0%BD%D0%B0_%D0%B8_%D0%91%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B0&amp;diff=65285"/>
				<updated>2018-05-10T09:22:18Z</updated>
		
		<summary type="html">&lt;p&gt;217.197.4.113: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Фарака-Колтона, Бендера''' (англ. ''Farach-Colton, Bender'') — применяется для решения за &amp;lt;tex&amp;gt;\langle O(N),O(1) \rangle&amp;lt;/tex&amp;gt; времени специального случая задачи &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Может быть использован также для [[Сведение задачи LCA к задаче RMQ|решения задачи &amp;lt;tex&amp;gt;\mathrm{LCA}&amp;lt;/tex&amp;gt;]].&lt;br /&gt;
&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Дан массив &amp;lt;tex&amp;gt;A[1 \ldots N]&amp;lt;/tex&amp;gt; целых чисел, соседние элементы которого отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Поступают онлайн запросы вида &amp;lt;tex&amp;gt;(l, r)&amp;lt;/tex&amp;gt;, для каждого из которых требуется найти минимум среди элементов &amp;lt;tex&amp;gt;A[l], A[l + 1], \ldots, A[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;\mathrm{RMQ}&amp;lt;/tex&amp;gt; с помощью [[Решение RMQ с помощью разреженной таблицы|разреженной таблицы]] за &amp;lt;tex&amp;gt;\langle O(N \log N),O(1) \rangle&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность &amp;lt;tex&amp;gt;A_i&amp;lt;/tex&amp;gt; на блоки длины &amp;lt;tex&amp;gt;K=\dfrac{1}{2}\log_2 N&amp;lt;/tex&amp;gt;. Для каждого блока вычислим минимум на нём и определим &amp;lt;tex&amp;gt;B_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;
&lt;br /&gt;
На новой последовательности &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; построим [[Решение RMQ с помощью разреженной таблицы|разреженную таблицу]]. При этом размер разреженной таблицы и время её построения будут равны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\dfrac{N}{K}\log\dfrac{N}{K}=\bigg(\dfrac{2N}{\log N}\bigg)\log\bigg(\dfrac{2N}{\log N}\bigg)=\bigg(\dfrac{2N}{\log N}\bigg)\bigg(1+\log\bigg(\dfrac{N}{\log N}\bigg)\bigg)\leqslant \dfrac{2N}{\log N}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;+2N=O(N)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь для ответа на запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;[l:r]&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;
* минимум на отрезке от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до конца блока, содержащего &amp;lt;tex&amp;gt;l&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;
* минимум от начала блока, содержащего &amp;lt;tex&amp;gt;r&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;
[[Файл:F-C_B_algo.png|500px|center|Части, из которых состоит ответ на запрос RMQ]]&lt;br /&gt;
&lt;br /&gt;
Второй элемент мы уже умеем находить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; с помощью &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; и разреженной таблицы. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.&lt;br /&gt;
&lt;br /&gt;
=== Минимум внутри блока ===&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=sameblocks&lt;br /&gt;
|statement=Если две последовательности &amp;lt;tex&amp;gt;x_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;y_i&amp;lt;/tex&amp;gt; таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. &amp;lt;tex&amp;gt;\forall k: x_k = y_k + C&amp;lt;/tex&amp;gt;), то любой запрос &amp;lt;tex&amp;gt;\mathrm{RMQ}&amp;lt;/tex&amp;gt; даст один и тот же ответ для обеих последовательностей.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Таким образом, мы можем ''нормализовать'' блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=kindscount&lt;br /&gt;
|statement=Существует &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; различных типов нормализованных блоков.&lt;br /&gt;
|proof=Соседние элементы в блоках отличаются на &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен &amp;lt;tex&amp;gt;\pm 1&amp;lt;/tex&amp;gt;-вектором длины &amp;lt;tex&amp;gt; \bigg(\dfrac{1}{2} \log_2 N\bigg) - 1&amp;lt;/tex&amp;gt;. Таких векторов &amp;lt;tex&amp;gt;2^{(\frac{1}{2} \log_2 N) - 1} = O(\sqrt N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Осталось создать &amp;lt;tex&amp;gt;O(\sqrt N)&amp;lt;/tex&amp;gt; таблиц {{---}} по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, которых &amp;lt;tex&amp;gt;\bigg(\dfrac{1}{2}\log_2 N\bigg)^2 = O(\log^2 N)&amp;lt;/tex&amp;gt;. Для каждого блока в &amp;lt;tex&amp;gt;B_i&amp;lt;/tex&amp;gt; необходимо заранее вычислить его тип. Для этого нужно подобрать некоторую функцию из множества блоков в множество натуральных чисел, не вызывающую коллизий. Например, вектор из нулей и единиц, соответствующий типу блока, можно записать в целочисленный тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, затратив на предподсчёт &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  '''function''' precalc(A: '''int[N]'''): &lt;br /&gt;
    block_size = log(N) / 2 &amp;lt;font color=green&amp;gt; // размеры блоков &amp;lt;/font&amp;gt;&lt;br /&gt;
    K = &amp;lt;tex&amp;gt;\lceil&amp;lt;/tex&amp;gt;N / block_size&amp;lt;tex&amp;gt;\rceil&amp;lt;/tex&amp;gt; &amp;lt;font color=green&amp;gt; // количество блоков &amp;lt;/font&amp;gt; &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// предподсчитаем позиции минимумов в каждом блоке&amp;lt;/font&amp;gt;&lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      B[i] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' N - 1&lt;br /&gt;
      '''if''' j &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' B[cur_block] = -1 '''or''' A[B[cur_block]] &amp;gt; A[i]&lt;br /&gt;
        B[cur_block] = i&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// построим Sparse table на массиве B&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      ST[i][0] = B[i]&lt;br /&gt;
    '''for''' j = 1 '''to''' log(N)&lt;br /&gt;
      '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
        ind = (1 &amp;lt;&amp;lt; (j - 1)) + i&lt;br /&gt;
        '''if''' ind &amp;lt;tex&amp;gt;\geq&amp;lt;/tex&amp;gt; K&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
        '''else if''' A[ST[i][j - 1]] &amp;gt; A[ST[ind][j - 1]]&lt;br /&gt;
          ST[i][j] = ST[ind][j - 1] &lt;br /&gt;
        '''else'''&lt;br /&gt;
          ST[i][j] = ST[i][j - 1]&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Посчитаем тип для каждого блока&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1 &lt;br /&gt;
      type[i] = 0 &lt;br /&gt;
    cur_block = 0&lt;br /&gt;
    j = 0&lt;br /&gt;
    i = 0&lt;br /&gt;
    '''while''' i &amp;lt; N or j &amp;lt; K&lt;br /&gt;
     '''if''' j &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; block_size &lt;br /&gt;
        j = 0&lt;br /&gt;
        cur_block++ &lt;br /&gt;
      '''if''' j &amp;gt; 0 '''and''' (i &amp;lt;tex&amp;gt;\geqslant&amp;lt;/tex&amp;gt; N '''or''' A[i - 1] &amp;lt; A[i])&lt;br /&gt;
        type[cur_block] += (1 &amp;lt;&amp;lt; (j - 1)) &lt;br /&gt;
      i++&lt;br /&gt;
      j++&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;// Осталось только для каждого блока предподсчитать позиции минимумов на всех подотрезках&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
        '''for''' r = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[i][l][r] = -1 &lt;br /&gt;
    '''for''' i = 0 '''to''' K - 1&lt;br /&gt;
      t = type[i]&lt;br /&gt;
      '''if''' block_min[t][0][0] = -1 &amp;lt;font color=green&amp;gt;// если там записано, что-то отличное от -1, то значит, мы уже посчитали ответ для такого типа отрезков&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''for''' l = 0 '''to''' block_size - 1&lt;br /&gt;
          block_min[t][l][l] = l&lt;br /&gt;
          '''for''' r = l + 1 '''to''' block_size - 1&lt;br /&gt;
            block_min[t][l][r] = block_min[t][l][r - 1]&lt;br /&gt;
            '''if''' i * block_size + r &amp;lt;tex&amp;gt;\leqslant &amp;lt;/tex&amp;gt; N '''and''' A[i * block_size + block_min[t][l][r]] &amp;gt; A[i * block_size + r]&lt;br /&gt;
                block_min[t][l][r] = r&lt;br /&gt;
&lt;br /&gt;
  '''function''' block_RMQ(block_number: '''int''', l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    '''return''' block_min[type[block_number]][l][r] + block_number * block_size&lt;br /&gt;
&lt;br /&gt;
  '''function''' RMQ(l: '''int''', r: '''int'''): '''int'''&lt;br /&gt;
    bl = l / block_size&lt;br /&gt;
    br = r / block_size&lt;br /&gt;
    '''if''' bl = br &amp;lt;font color=green&amp;gt;// если оба индекса внутри одного блока&amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' A[block_RMQ(bl, l % block_size, r % block_size)]&lt;br /&gt;
    '''if''' bl + 1 &amp;lt; br &amp;lt;font color=green&amp;gt;// найдем минимум на блоках между крайними, если таковые есть&amp;lt;/font&amp;gt;&lt;br /&gt;
      power = log(br - bl + 1)&lt;br /&gt;
      ansb = min(A[ST[bl + 1][power]], A[ST[br - (1 &amp;lt;&amp;lt; power)][power]])&lt;br /&gt;
    ansl = A[block_RMQ(bl, l % block_size, block_size - 1)] &amp;lt;font color=green&amp;gt;// найдем минимум на отрезке от l до конца блока, содержащего l&amp;lt;/font&amp;gt;&lt;br /&gt;
    ansr = A[block_RMQ(bl, 0, r % block_size)] &amp;lt;font color=green&amp;gt;// найдем минимум от начала блока, содержащего r, до r &amp;lt;/font&amp;gt;   &lt;br /&gt;
    '''return''' min(ansb, min(ansl, ansr))&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Результат ===&lt;br /&gt;
Итого, на предподсчёт требуется &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени и памяти, а ответ на запрос вычисляется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Решение RMQ с помощью разреженной таблицы]]&lt;br /&gt;
* [[Сведение задачи RMQ к задаче LCA]]&lt;br /&gt;
* [[Сведение задачи LCA к задаче RMQ]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Bender, M.A., Farach-Colton, M. {{---}} The LCA Problem Revisited. LATIN (2000), с. 88-94&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Задача о наименьшем общем предке]]&lt;/div&gt;</summary>
		<author><name>217.197.4.113</name></author>	</entry>

	</feed>