Сведение задачи RMQ к задаче LCA — различия между версиями
Строка 1: | Строка 1: | ||
== Постановка задачи RMQ == | == Постановка задачи RMQ == | ||
+ | [[Файл:Wiki.PNG|thumb|right|300x160px|Пример построенного дерева для массива А]] | ||
Дан массив <tex>A[1..N]</tex>. Поступают запросы вида <tex>(i, j)</tex>, на каждый запрос требуется найти минимум в массиве <tex>A</tex>, начиная с позиции <tex>i</tex> и заканчивая позицией <tex>j</tex>. | Дан массив <tex>A[1..N]</tex>. Поступают запросы вида <tex>(i, j)</tex>, на каждый запрос требуется найти минимум в массиве <tex>A</tex>, начиная с позиции <tex>i</tex> и заканчивая позицией <tex>j</tex>. | ||
== Алгоритм == | == Алгоритм == | ||
− | |||
Декартово дерево (англ. ''сartesian tree'') на массиве <tex>A[1..N]</tex> {{---}} это бинарное дерево, рекурсивно определенное следующим образом: | Декартово дерево (англ. ''сartesian tree'') на массиве <tex>A[1..N]</tex> {{---}} это бинарное дерево, рекурсивно определенное следующим образом: | ||
* Корнем дерева является минимальное значение в массиве <tex>A</tex>, скажем <tex>A[i]</tex>. Если минимальных значений несколько, можно взять любое. | * Корнем дерева является минимальное значение в массиве <tex>A</tex>, скажем <tex>A[i]</tex>. Если минимальных значений несколько, можно взять любое. | ||
Строка 9: | Строка 9: | ||
Построим декартово дерево на массиве <tex>A</tex>. Тогда <tex>RMQ(i, j)</tex> = <tex>LCA(A[i], A[j])</tex>. | Построим декартово дерево на массиве <tex>A</tex>. Тогда <tex>RMQ(i, j)</tex> = <tex>LCA(A[i], A[j])</tex>. | ||
== Доказательство == | == Доказательство == | ||
+ | {{Теорема | ||
+ | |statement= | ||
+ | Приведенный выше алгоритм работает верно. | ||
+ | |proof= | ||
Мы знаем что: | Мы знаем что: | ||
* Любая вершина дерева всегда имеет меньшее значение, чем её дети. Тогда любой предок <tex>A[i]</tex> или <tex>A[j]</tex> меньше их самих. | * Любая вершина дерева всегда имеет меньшее значение, чем её дети. Тогда любой предок <tex>A[i]</tex> или <tex>A[j]</tex> меньше их самих. | ||
* <tex>LCA(A[i], A[j])</tex> ближайший к корню и по п.1 имеет наименьшее значение в своем поддереве. По построению, это поддерево содержит в частности подмассив <tex>A[i..j], </tex> и <tex>LCA(A[i], A[j])</tex> находится между <tex>A[i]</tex> и <tex>A[j]</tex>. То есть <tex>LCA(A[i], A[j])</tex> является <tex>RMQ(i, j).</tex> | * <tex>LCA(A[i], A[j])</tex> ближайший к корню и по п.1 имеет наименьшее значение в своем поддереве. По построению, это поддерево содержит в частности подмассив <tex>A[i..j], </tex> и <tex>LCA(A[i], A[j])</tex> находится между <tex>A[i]</tex> и <tex>A[j]</tex>. То есть <tex>LCA(A[i], A[j])</tex> является <tex>RMQ(i, j).</tex> | ||
+ | }} | ||
== Построение дерева за линейное время == | == Построение дерева за линейное время == | ||
Пусть дан массив <tex>A[1..N]</tex>. Будем по очереди слева на право добавлять элементы в дерево. Чтобы добавить новое значение <tex>A[i]</tex>, начнем обход из вершины <tex>A[i-1]</tex> к корню, пока не найдем вершину <tex>x</tex>, для которой <tex>x < A[i]</tex>. Тогда правого сына <tex>x</tex> назначим левым сыном <tex>A[i]</tex>, а <tex>A[i]</tex> {{---}} правым сыном <tex>x</tex>. Рассмотрим правую ветку дерева, т.е. по которой проходит обход алгоритма. Заметим, что при добавлении нового узла в дерево элементы, по которым только что прошелся алгоритм отправляются налево, т.е. перестают принадлежать правой ветке. Таким образом процедура поиска родителя не сможет выполнится более <tex>n</tex> раз и итоговая асимптотика алгоритма <tex>O(n)</tex>. | Пусть дан массив <tex>A[1..N]</tex>. Будем по очереди слева на право добавлять элементы в дерево. Чтобы добавить новое значение <tex>A[i]</tex>, начнем обход из вершины <tex>A[i-1]</tex> к корню, пока не найдем вершину <tex>x</tex>, для которой <tex>x < A[i]</tex>. Тогда правого сына <tex>x</tex> назначим левым сыном <tex>A[i]</tex>, а <tex>A[i]</tex> {{---}} правым сыном <tex>x</tex>. Рассмотрим правую ветку дерева, т.е. по которой проходит обход алгоритма. Заметим, что при добавлении нового узла в дерево элементы, по которым только что прошелся алгоритм отправляются налево, т.е. перестают принадлежать правой ветке. Таким образом процедура поиска родителя не сможет выполнится более <tex>n</tex> раз и итоговая асимптотика алгоритма <tex>O(n)</tex>. |
Версия 19:13, 20 апреля 2012
Содержание
Постановка задачи RMQ
Дан массив
. Поступают запросы вида , на каждый запрос требуется найти минимум в массиве , начиная с позиции и заканчивая позицией .Алгоритм
Декартово дерево (англ. сartesian tree) на массиве
— это бинарное дерево, рекурсивно определенное следующим образом:- Корнем дерева является минимальное значение в массиве , скажем . Если минимальных значений несколько, можно взять любое.
- Левым поддеревом является декартово дерево на массиве .
- Правым поддеревом является декартово дерево на массиве .
Построим декартово дерево на массиве
. Тогда = .Доказательство
Теорема: |
Приведенный выше алгоритм работает верно. |
Доказательство: |
Мы знаем что:
|
Построение дерева за линейное время
Пусть дан массив
. Будем по очереди слева на право добавлять элементы в дерево. Чтобы добавить новое значение , начнем обход из вершины к корню, пока не найдем вершину , для которой . Тогда правого сына назначим левым сыном , а — правым сыном . Рассмотрим правую ветку дерева, т.е. по которой проходит обход алгоритма. Заметим, что при добавлении нового узла в дерево элементы, по которым только что прошелся алгоритм отправляются налево, т.е. перестают принадлежать правой ветке. Таким образом процедура поиска родителя не сможет выполнится более раз и итоговая асимптотика алгоритма .Сложность
Выше описан алгоритм построения дерева за
. Препроцессинг для — и ответ на запрос . В итоге получили {построение , запрос }.