Реализация запроса в дереве отрезков сверху — различия между версиями
Gr1n (обсуждение | вклад) (→Алгоритм) |
Gr1n (обсуждение | вклад) (→Реализация) |
||
Строка 44: | Строка 44: | ||
<code> | <code> | ||
− | int | + | int get_sum (int ver, int l, int r, int a, int b) |
{ | { | ||
− | if ([l,r] <tex>\bigcap</tex> [ | + | if ([l,r] <tex>\bigcap</tex> [a, b] = <tex> \varnothing</tex>) |
return 0; | return 0; | ||
− | if ([l,r] = [ | + | if ([l,r] = [a, b]) |
− | return | + | return tree[ver]; |
− | int | + | int m = (l + r) / 2; |
− | return | + | return get_sum (ver * 2, l, m, a, min(b, m)) |
− | + | + | + get_sum (ver * 2 + 1, m + 1, r, max(a, m + 1), b); |
} | } | ||
</code> | </code> |
Версия 18:43, 20 апреля 2012
Содержание
Описание
Данная рекурсивная операция позволяет выполнять запросы на дереве отрезков, причем алгоритм запускается от корня и рекурсивно идет сверху вниз.
Алгоритм
Рассмотрим данный алгоритм на примере задачи 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); }