
- •Граф. Ориентированный граф. Представления графа. Обход графа в глубину и в ширину.
- •Топологическая сортировка. Подсчет числа путей в орграфе.
- •Сильно связные компоненты.
- •Поиск кратчайших путей в графе. Алгоритм Флойда. Алгоритм Дейкстры. Алгоритм Форда-Беллмана.
- •Алгоритм a*. Эвристики.
- •Минимальное остовное дерево. Алгоритм Прима. Биномиальная куча.
- •Амортизационная стоимость. Фибоначчиева куча. Амортизационная стоимость (анализ)
- •Метод потенциалов
- •Фибоначчиева Куча
- •Структура
- •Время работы
- •Система непересекающихся множеств. Алгоритм Крускала.
- •Наивная реализация
- •Эвристика сжатия пути
- •Эвристика объединения по рангу
- •Потоки, Форда-Фалкерсона.
- •Декартово дерево
- •Дерево Фенвика. Дерево отрезков и динамическое программирование для rmq.
- •Сведение rmq к lca и наоборот.
- •Препроцессинг
- •Ответы на запросы
- •Алгоритм
- •Доказательство
- •Сложность
- •Алгоритм
- •Минимум внутри блока
- •Результат
- •Поиск нескольких минимумов на отрезке. Задача поиска подстрок. Алгоритм Рабина-Карпа. Конечный автомат. Алгоритм Бойера-Мура.
- •Метод хеширования
- •Алгоритм
- •Время работы
- •Алгоритм Бойера-Мура
- •Поиск со звездочками. Алгоритм Кнута-Морриса-Пратта.
- •Время работы
- •Алгоритм Ахо-Корасика.
- •Дерево ключевых слов (бор)
- •Пример дерева ключевых слов (бора)
- •Построение бора
- •Поиск строки в бору
- •Автомат Ахо-Корасик
- •Суффиксное дерево, Алгоритм Укконена.
- •2. Квадратичный алгоритм
- •3. Линейный алгоритм
- •Суффиксный массив.
- •Наивный алгоритм поиска
- •Алгоритм, использующий префиксы циклических сдвигов
- •Исключения
- •Шаблоны
- •Stl: итераторы
- •Сортировка и поиск в stl. Алгоритмы stl
- •Куча в stl. Алгоритмы stl.
- •Ассоциативный массив. Интерфейс, варианты реализации.
Ответы на запросы
Ответы
на запросы будут происходить за время
.
Для ответа на запрос заметим сначала,
что если
,
для некоторых
и
,
то
.
Поэтому если
,
то пройдем от вершины
на
шагов
вверх, это и будет новое значение
и
это можно сделать за
.
Можно записать число
в
двоичной системе, это представление
этого число в виде суммы степеней двоек,
и
для всех
пройти
вверх последовательно из вершины
в
.
Дальше
считаем, что
.
Если
,
то ответ на запрос
.
А
если
,
то найдем такие вершины
и
,
такие что
,
—
предок
,
—
предок
и
.
Тогда ответом на запрос будет
.
Научимся
находить эти вершины
и
.
Для этого сначала инициализируем
и
.
Дальше на каждом шаге находим такое
максимальное
,
что
.
И проходим из вершин
и
на
шагов
вверх. Если такого
найти нельзя, то значения
и
,
это те самые вершины, которые нам
требуется найти, ведь
.
Оценим
время работы. Заметим, что найденные
строго
убывают. Во-первых, потому что мы находим
на каждом шаге максимальное значение
,
а во-вторых, два раза подряд мы одно и
то же
получить
не можем, так как тогда получилось бы,
что можно пройти
шагов,
а значит вместо первого
,
мы бы нашли
.
А значит всего
значений
,
их можно перебирать в порядке убывания.
Сложность ответа на запрос
.
Псевдокод
preprocess()
p
:= dfs(0)
for i := 1 .. n
dp[i][0]
:= p[i]
for j := 1 .. log(n)
for
i := 1 .. n
dp[i][j] :=
dp[dp[i][j - 1]][j - 1]
lca(v,
u)
if (d[v] > d[u])
swap(v,
u)
for i := log(n) .. 0
if
(d[u] - d[v] >=
)
u
:= dp[u][i]
if (v = u)
return
v
for i := log(n) .. 0
if
(dp[v][i] <> dp[u][i])
v
:= dp[v][i]
u :=
dp[u][i]
return p[v]
Алгоритм с предпроцессингом (Сведение LCA к RMQ) Для каждой вершины определим глубину с помощью следующей рекурсивной формулы:
Ясно, что глубина вершины элементарным образом поддерживается во время обхода в глубину. Запустим обход в глубину из корня, который будет вычислять значения следующих величин:
Cписок глубин посещенных вершин . Глубина текущей вершины добавляется в конец списка при входе в данную вершину, а также после каждого возвращения из её сына.
Список посещений узлов
, строящийся аналогично предыдущему, только добавляется не глубина а сама вершина.
Значение функции
, возвращающей любой индекс в списке глубин , по которому была записана глубина вершины (например на момент входа в вершину).
Запрос
Будем
считать, что
возвращает
индекс минимального элемента в
на
отрезке
.
Тогда ответом на запрос
,
где
,
будет
.
RMQ через LCA
Дан
массив
.
Поступают запросы вида
,
на каждый запрос требуется найти минимум
в массиве
,
начиная с позиции
и
заканчивая позицией
.
Алгоритм
Декартово дерево (англ. сartesian tree) по неявному ключу на массиве — это бинарное дерево, допускающее следующее рекурсивное построение:
Корнем дерева является элемент массива, имеющий минимальное значение , скажем
. Если минимальных элементов несколько, можно взять любой.
Левым поддеревом является декартово дерево на массиве
.
Правым поддеревом является декартово дерево на массиве
.
Здесь и далее будет также использоваться для обозначения соответствующей вершины дерева.
Построим
декартово дерево на массиве
.
Тогда
=
.