Реализация запроса в дереве отрезков сверху — различия между версиями
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);
}