Реализация запроса в дереве отрезков сверху
Содержание
Описание
Данная рекурсивная операция позволяет выполнять запросы на дереве отрезков, причем алгоритм запускается от корня и рекурсивно идет сверху вниз.
Алгоритм
Рассмотрим данный алгоритм на примере задачи RSQ(запрос суммы на отрезке), то есть пусть есть уже построенное дерево отрезков и задача найти сумму на отрезке
.Будем передавать в качестве параметров рекурсий следующие переменные:
- — номер(в массиве с деревом отрезков) текущей вершины дерева.
- , — левая и правая границы отрезков, за которые "отвечает" наша вершина.
- , — левая и правая границы запрашиваемого отрезка.
Запустим рекурсивную процедуру от всего отрезка(то есть от корневой вершины).
Для текущего состояния проверяем следующие условия :
- Если текущий отрезок не пересекается с искомым, то возвращаем нулевое значение.
Например: текущий
, а искомый ;- Текущий отрезок совпадает, то возвращаем значение в текущей вершине.
Например: текущий и искомый
;- Иначе переходим к рекурсивным вызовам функций от детей вершины. При этом сумма на текущем отрезке равна сумме результатов функций, запущенных от детей.
Пример
Рассмотрим работу программы на дереве отрезков для элементов
. Пусть запрашиваемая сумма - это отрезок .- Текущий отрезок , он больше => переходим по рекурсивным вызовам на и
- выходит за границы , выходит за границы => переходим по рекурсивным вызовам на , и , .
- выходит за границы => переходим в листья 1, 2; целиком внутри => возвращаем значение в ;
не пересекается с => возвращаем нулевое значение, выходит за границы => переходим к листьям 5 и 6
- лист 6 не пересекается с отрезком => возвращаем нулевое значение, лист 5 целиков внутри => возвращаем значение в листе 5.
Реализация
int sum (int v, int tl, int tr, int l, int r)
{
if ([l,r]
[tl, tr]) =
return 0;
if ([l,r] = [tl, tr])
return t[v];
int tm = (tl + tr) / 2;
return sum (v*2, tl, tm, l, min(r,tm))
+ sum (v*2+1, tm+1, tr, max(l,tm+1), r);
}