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