Сведение RMQ к LCA и наоборот.

LCA (least common ancestor)

Задача LCA (наименьший общий предок) для двух вершин Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru в корневом дереве Сведение RMQ к LCA и наоборот. - student2.ru называется узел Сведение RMQ к LCA и наоборот. - student2.ru , который среди всех узлов, являющихся предками как узла Сведение RMQ к LCA и наоборот. - student2.ru , так и Сведение RMQ к LCA и наоборот. - student2.ru , имеет наибольшую глубину. Пусть дано корневое дерево Сведение RMQ к LCA и наоборот. - student2.ru . На вход подаются запросы вида Сведение RMQ к LCA и наоборот. - student2.ru , для каждого запроса требуется найти их наименьшего общего предка.
Четыре основных алгоритма:

0. Самый простой, наивный алгоритм для нахождения наименьшего общего предка — вычислить глубину вершин u и v и постепенно подниматься из каждой вершины вверх по дереву, пока не будет найдена общая вершина:

Процедура LCA(u, v):

h1 := depth(u) // depth(x) = глубина вершины x

h2 := depth(v)

while h1 ≠ h2:

if h1 > h2:

u := parent(u)

h1 := h1 - 1

else:

v := parent(v)

h2 := h2 - 1

whileu ≠ v:

u := parent(u) // parent(x) = непосредственный предок вершины x

v := parent(v)

returnu

Время работы этого алгоритма составляет O(h), где h — высота дерева. Кроме того, может понадобиться препроцессинг, требующий O(n) времени, для нахождения непосредственного предка для всех вершин дерева и глубины вершин (но, как правило, эта структура на дереве уже имеется) – делается обходом графа.

1. Алгоритм за O(sqrt(H)).
шаг первый: BFS– узнаем глубину дерева и глубину каждой из вершин

Шаг второй: DFS – Делим на уровни длиной sqrt(H) (их всего будет sqrt(H)). Для каждой вершины считаем d[v] = первый предок из предыдущего уровня.

Как считать? Если глубина вершины кратна sqrt(H), значит они или первая, или последняя в уровне – обрабатываем отдельно. Иначе d[v] = d[u], где u – прямой предок v.
Итого предпроцессинг за O(H).
Запрос:

Если вершины на разных уровнях – прыгаем из вершины с меньшим уровнем, пока уровень не будет одинаковым (максимум – O(sqrtH)). Когда достигли одного уровня, то P[v] = P[u], то LCAu,vнаходится между ними и вершиной P[u] = P[v]. Просто поднимаемся вверх (по прямым родителям), пока не окажемся в одной вершине. Если P[u] != P[v] – максимум за O(sqrt(H)).

Итого алгоритм работает за <O(N), O(sqrtH)>

2. Метод двоичного подъема
Данный алгоритм является on-line (то есть сначала делается препроцессинг, затем алгоритм работает в формате запрос-ответ).

Препроцессинг

Препроцессинг заключается в том, чтобы посчитать функцию: Сведение RMQ к LCA и наоборот. - student2.ru — номер вершины, в которую мы придем если пройдем из вершины Сведение RMQ к LCA и наоборот. - student2.ru вверх по подвешенному дереву Сведение RMQ к LCA и наоборот. - student2.ru шагов, причем если мы пришли в корень, то мы там и останемся. Для этого сначала обойдем дерево в глубину и для каждой вершины запишем номер ее родителя Сведение RMQ к LCA и наоборот. - student2.ru и глубину вершины в подвешенном дереве Сведение RMQ к LCA и наоборот. - student2.ru . Если Сведение RMQ к LCA и наоборот. - student2.ru — корень, то Сведение RMQ к LCA и наоборот. - student2.ru . Тогда для функции Сведение RMQ к LCA и наоборот. - student2.ru есть рекуррентная формула: Сведение RMQ к LCA и наоборот. - student2.ru

Ведь 2i-1+2i-1=2i
Для того чтобы отвечать на запросы нам нужны будут только те значения Сведение RMQ к LCA и наоборот. - student2.ru , где Сведение RMQ к LCA и наоборот. - student2.ru , ведь при больших Сведение RMQ к LCA и наоборот. - student2.ru значение Сведение RMQ к LCA и наоборот. - student2.ru будет номером корня.
Всего состояний динамики Сведение RMQ к LCA и наоборот. - student2.ru , где Сведение RMQ к LCA и наоборот. - student2.ru — это количество вершин в дереве. Каждое состояние считается за Сведение RMQ к LCA и наоборот. - student2.ru . Поэтому суммарная сложность времени и памяти препроцессинга — Сведение RMQ к LCA и наоборот. - student2.ru .

Ответы на запросы

Ответы на запросы будут происходить за время Сведение RMQ к LCA и наоборот. - student2.ru . Для ответа на запрос заметим сначала, что если Сведение RMQ к LCA и наоборот. - student2.ru , для некоторых Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru , то Сведение RMQ к LCA и наоборот. - student2.ru . Поэтому если Сведение RMQ к LCA и наоборот. - student2.ru , то пройдем от вершины Сведение RMQ к LCA и наоборот. - student2.ru на Сведение RMQ к LCA и наоборот. - student2.ru шагов вверх, это и будет новое значение Сведение RMQ к LCA и наоборот. - student2.ru и это можно сделать за Сведение RMQ к LCA и наоборот. - student2.ru . Можно записать число Сведение RMQ к LCA и наоборот. - student2.ru в двоичной системе, это представление этого число в виде суммы степеней двоек, Сведение RMQ к LCA и наоборот. - student2.ru и для всех Сведение RMQ к LCA и наоборот. - student2.ru пройти вверх последовательно из вершины Сведение RMQ к LCA и наоборот. - student2.ru в Сведение RMQ к LCA и наоборот. - student2.ru .

Дальше считаем, что Сведение RMQ к LCA и наоборот. - student2.ru .

Если Сведение RMQ к LCA и наоборот. - student2.ru , то ответ на запрос Сведение RMQ к LCA и наоборот. - student2.ru .

А если Сведение RMQ к LCA и наоборот. - student2.ru , то найдем такие вершины Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru , такие что Сведение RMQ к LCA и наоборот. - student2.ru , Сведение RMQ к LCA и наоборот. - student2.ru — предок Сведение RMQ к LCA и наоборот. - student2.ru , Сведение RMQ к LCA и наоборот. - student2.ru — предок Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru . Тогда ответом на запрос будет Сведение RMQ к LCA и наоборот. - student2.ru .
Научимся находить эти вершины Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru . Для этого сначала инициализируем Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru . Дальше на каждом шаге находим такое максимальное Сведение RMQ к LCA и наоборот. - student2.ru , что Сведение RMQ к LCA и наоборот. - student2.ru . И проходим из вершин Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru на Сведение RMQ к LCA и наоборот. - student2.ru шагов вверх. Если такого Сведение RMQ к LCA и наоборот. - student2.ru найти нельзя, то значения Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru , это те самые вершины, которые нам требуется найти, ведь Сведение RMQ к LCA и наоборот. - student2.ru .
Оценим время работы. Заметим, что найденные Сведение RMQ к LCA и наоборот. - student2.ru строго убывают. Во-первых, потому что мы находим на каждом шаге максимальное значение Сведение RMQ к LCA и наоборот. - student2.ru , а во-вторых, два раза подряд мы одно и то же Сведение RMQ к LCA и наоборот. - student2.ru получить не можем, так как тогда получилось бы, что можно пройти Сведение RMQ к LCA и наоборот. - student2.ru шагов, а значит вместо первого Сведение RMQ к LCA и наоборот. - student2.ru , мы бы нашли Сведение RMQ к LCA и наоборот. - student2.ru . А значит всего Сведение RMQ к LCA и наоборот. - student2.ru значений Сведение RMQ к LCA и наоборот. - student2.ru , их можно перебирать в порядке убывания. Сложностьответаназапрос Сведение RMQ к LCA и наоборот. - student2.ru .
Псевдокод
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] >= Сведение RMQ к LCA и наоборот. - student2.ru )
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]

3. Алгоритм с предпроцессингом (Сведение LCA к RMQ)
Для каждой вершины Сведение RMQ к LCA и наоборот. - student2.ru определим глубину с помощью следующей рекурсивной формулы: Сведение RMQ к LCA и наоборот. - student2.ru
Ясно, что глубина вершины элементарным образом поддерживается во время обхода в глубину.
Запустим обход в глубину из корня, который будет вычислять значения следующих величин:

1. Cписок глубин посещенных вершин Сведение RMQ к LCA и наоборот. - student2.ru . Глубина текущей вершины добавляется в конец списка при входе в данную вершину, а также после каждого возвращения из её сына.

2. Список посещений узлов Сведение RMQ к LCA и наоборот. - student2.ru , строящийся аналогично предыдущему, только добавляется не глубина а сама вершина.

3. Значение функции Сведение RMQ к LCA и наоборот. - student2.ru , возвращающей любой индекс в списке глубин Сведение RMQ к LCA и наоборот. - student2.ru , по которому была записана глубина вершины Сведение RMQ к LCA и наоборот. - student2.ru (например на момент входа в вершину).

Запрос

Будем считать, что Сведение RMQ к LCA и наоборот. - student2.ru возвращает индекс минимального элемента в Сведение RMQ к LCA и наоборот. - student2.ru на отрезке Сведение RMQ к LCA и наоборот. - student2.ru . Тогда ответом на запрос Сведение RMQ к LCA и наоборот. - student2.ru , где Сведение RMQ к LCA и наоборот. - student2.ru , будет Сведение RMQ к LCA и наоборот. - student2.ru .

RMQ через LCA

Сведение RMQ к LCA и наоборот. - student2.ru

Сведение RMQ к LCA и наоборот. - student2.ru

Дан массив Сведение RMQ к LCA и наоборот. - student2.ru . Поступают запросы вида Сведение RMQ к LCA и наоборот. - student2.ru , на каждый запрос требуется найти минимум в массиве Сведение RMQ к LCA и наоборот. - student2.ru , начиная с позиции Сведение RMQ к LCA и наоборот. - student2.ru и заканчивая позицией Сведение RMQ к LCA и наоборот. - student2.ru .

Алгоритм

Декартово дерево (англ. сartesian tree) по неявному ключу на массиве Сведение RMQ к LCA и наоборот. - student2.ru — это бинарное дерево, допускающее следующее рекурсивное построение:

§ Корнем дерева является элемент массива, имеющий минимальное значение Сведение RMQ к LCA и наоборот. - student2.ru , скажем Сведение RMQ к LCA и наоборот. - student2.ru . Если минимальных элементов несколько, можно взять любой.

§ Левым поддеревом является декартово дерево на массиве Сведение RMQ к LCA и наоборот. - student2.ru .

§ Правым поддеревом является декартово дерево на массиве Сведение RMQ к LCA и наоборот. - student2.ru .

Здесь и далее Сведение RMQ к LCA и наоборот. - student2.ru будет также использоваться для обозначения соответствующей вершины дерева.

Построим декартово дерево на массиве Сведение RMQ к LCA и наоборот. - student2.ru . Тогда Сведение RMQ к LCA и наоборот. - student2.ru = Сведение RMQ к LCA и наоборот. - student2.ru .

Доказательство

Теорема:
Сведение RMQ к LCA и наоборот. - student2.ru = Сведение RMQ к LCA и наоборот. - student2.ru .
Доказательство:
Сведение RMQ к LCA и наоборот. - student2.ru
Положим Сведение RMQ к LCA и наоборот. - student2.ru . Заметим, что Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru не принадлежат одновременно либо правому, либо левому поддереву Сведение RMQ к LCA и наоборот. - student2.ru , потому как тогда бы соответствующий сын находился на большей глубине, чем Сведение RMQ к LCA и наоборот. - student2.ru , и также являлся предком как Сведение RMQ к LCA и наоборот. - student2.ru так и Сведение RMQ к LCA и наоборот. - student2.ru , что противоречит определению Сведение RMQ к LCA и наоборот. - student2.ru . Из этого замечанию следует, что Сведение RMQ к LCA и наоборот. - student2.ru лежит между Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru и, следовательно, принадлежит отрезку Сведение RMQ к LCA и наоборот. - student2.ru . По построению мы также знаем, что: 1. Любая вершина дерева имеет свое значение меньшим либо равным значению её детей. 2. Поддерево с корнем в Сведение RMQ к LCA и наоборот. - student2.ru содержит в себе подмассив Сведение RMQ к LCA и наоборот. - student2.ru . Суммируя, получаем, что Сведение RMQ к LCA и наоборот. - student2.ru имеет минимальное значение на отрезке, покрывающем Сведение RMQ к LCA и наоборот. - student2.ru , и принадлежит отрезку Сведение RMQ к LCA и наоборот. - student2.ru , отсюда Сведение RMQ к LCA и наоборот. - student2.ru .
Сведение RMQ к LCA и наоборот. - student2.ru

Сложность

Следующий алгоритм строит декартово дерево за Сведение RMQ к LCA и наоборот. - student2.ru . Используя Сведение задачи LCA к задаче RMQ, получаем: препроцессинг для Сведение RMQ к LCA и наоборот. - student2.ruСведение RMQ к LCA и наоборот. - student2.ru и ответ на запрос — Сведение RMQ к LCA и наоборот. - student2.ru . В итоге получили Сведение RMQ к LCA и наоборот. - student2.ru с построением за Сведение RMQ к LCA и наоборот. - student2.ru и ответом на запрос за Сведение RMQ к LCA и наоборот. - student2.ru .

Процесс построения дучи по массиву:

Stack.push(A[0])

For (i = 1; i < n; i++)

If(A[i] >= A[stack.top])

s.top()->right = i;

s.push(i);

else

while(A[i] < A[s.top])

cur = s.top();

s.pop();

i->left = cur;

s.top()->right = I;

s.push(i);

Restricted RMQ

Алгоритм Фарака-Колтона, Бендера (алгоритм Фарах-Колтона, Бендера) — применяется для решения за Сведение RMQ к LCA и наоборот. - student2.ru времени специального случая задачи RMQ (поиск минимума на отрезке), в котором соседние элементы входной последовательности различаются на ±1. Может быть использован также для решения задачи LCA.

Вход: последовательность Сведение RMQ к LCA и наоборот. - student2.ru длины Сведение RMQ к LCA и наоборот. - student2.ru , соседние элементы которой отличаются на ±1.
Выход: ответы на онлайн запросы вида «позиция минимума на отрезке Сведение RMQ к LCA и наоборот. - student2.ru ».

Алгоритм

Части, из которых состоит ответ на запрос RMQ

Данный алгоритм основывается на методе решения задачи RMQ с помощью разреженной таблицы (sparse table, ST) за Сведение RMQ к LCA и наоборот. - student2.ru .

Чтобы избавиться от логарифма используется предподсчёт ответа для небольших подстрок входной последовательности. Разделим последовательность Сведение RMQ к LCA и наоборот. - student2.ru на блоки длины Сведение RMQ к LCA и наоборот. - student2.ru . Для каждого блока вычислим минимум на нём и определим Сведение RMQ к LCA и наоборот. - student2.ru как позицию минимального элемента в Сведение RMQ к LCA и наоборот. - student2.ru -том блоке.

На новой последовательности Сведение RMQ к LCA и наоборот. - student2.ru построим разреженную таблицу. Теперь для ответа на запрос RMQ Сведение RMQ к LCA и наоборот. - student2.ru , если Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru находятся в разных блоках, нам необходимо вычислить следующее:

1. минимум на отрезке от Сведение RMQ к LCA и наоборот. - student2.ru до конца содержащего Сведение RMQ к LCA и наоборот. - student2.ru блока;

2. минимум по всем блокам, находящимся между блоками, содержащими Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru ;

3. минимум от начала блока, содержащего Сведение RMQ к LCA и наоборот. - student2.ru , до Сведение RMQ к LCA и наоборот. - student2.ru .

Ответом на запрос будет позиция меньшего из эти трёх элементов.

Второй элемент мы уже умеем находить за Сведение RMQ к LCA и наоборот. - student2.ru с помощью Сведение RMQ к LCA и наоборот. - student2.ru и ST. Осталось научиться находить минимум по отрезку, границы которого не совпадают с границами блоков.

Минимум внутри блока

Утверждение:
Если две последовательности Сведение RMQ к LCA и наоборот. - student2.ru и Сведение RMQ к LCA и наоборот. - student2.ru таковы, что все их элементы на соответствующих позициях различаются на одну и ту же константу (т.е. Сведение RMQ к LCA и наоборот. - student2.ru ), то любой запрос RMQ даст один и тот же ответ для обеих последовательностей.

Таким образом, мы можем нормализовать блок, вычтя из всех его элементов первый. Тем самым мы значительно уменьшим число возможных типов блоков.

Утверждение:
Существует Сведение RMQ к LCA и наоборот. - student2.ru различных типов нормализованных блоков.
Сведение RMQ к LCA и наоборот. - student2.ru
Соседние элементы в блоках отличаются на ±1. Первый элемент в нормализованном блоке всегда равен нулю. Таким образом, каждый нормализованный блок может быть представлен ±1-вектором длины Сведение RMQ к LCA и наоборот. - student2.ru . Таких векторов Сведение RMQ к LCA и наоборот. - student2.ru .
Сведение RMQ к LCA и наоборот. - student2.ru

Осталось создать Сведение RMQ к LCA и наоборот. - student2.ru таблиц — по одной для каждого типа блока. В такую таблицу необходимо занести предподсчитанные ответы на все возможные запросы минимума внутри блока соответствующего типа, коих Сведение RMQ к LCA и наоборот. - student2.ru . Для каждого блока в Сведение RMQ к LCA и наоборот. - student2.ru необходимо заранее вычислить его тип. Таким образом мы получили возможность отвечать на запрос минимума по любой части блока за Сведение RMQ к LCA и наоборот. - student2.ru , затратив на предподсчёт Сведение RMQ к LCA и наоборот. - student2.ru времени.

Результат

Итого, на предподсчёт требуется Сведение RMQ к LCA и наоборот. - student2.ru времени и памяти, а ответ на запрос вычисляется за Сведение RMQ к LCA и наоборот. - student2.ru .


Наши рекомендации