Несогласованные поддеревья. Реализация массового обновления — различия между версиями
(→Массовое обновление) |
|||
Строка 1: | Строка 1: | ||
− | Дерево отрезков позволяет осуществлять так называемые '''массовые операций''', то есть данная структура позволяет выполнять операций с несколькими подряд идущими элементами. Причем время работы, как и при других запросах, равно <tex>O(\log n)</tex>. | + | [[Дерево отрезков. Построение|Дерево отрезков]] позволяет осуществлять так называемые '''массовые операций''', то есть данная структура позволяет выполнять операций с несколькими подряд идущими элементами. Причем время работы, как и при других запросах, равно <tex>O(\log n)</tex>. |
==Несогласованные поддеревья== | ==Несогласованные поддеревья== |
Версия 23:08, 6 июня 2012
Дерево отрезков позволяет осуществлять так называемые массовые операций, то есть данная структура позволяет выполнять операций с несколькими подряд идущими элементами. Причем время работы, как и при других запросах, равно .
Несогласованные поддеревья
Сперва рассмотрим так называемые несогласованные поддеревья.
В несогласованном поддереве дерева отрезков в вершинах хранятся не истинные значения сумм (по операции
) на отрезках, однако гарантируется, что на запрос они отвечают верно. При этом в корне поддерева, которому соответствует отрезок хранится несогласованность . Если в вершине хранится истинное значение суммы, то — нейтральный элемент относительно операции (например 0 для прибавления). Для реализации вторая операция должна быть ассоциативной, и операций должны удовлетворять свойству дистрибутивности:Массовое обновление
Рассмотрим в общем виде реализацию массовой операций на отрезке. Пусть необходимо отвечать запросы относительно операций
, а запрос массового обновления идет по операций .Для эффективной реализаций будем использовать описанную выше структуру — несогласованные поддеревья. В каждой вершине, помимо непосредственно результата выполнения операций
, храним несогласованность — величина, с которой нужно выполнить операцию для всех элементов текущего отрезка. Тем самым мы сможем обрабатывать запрос массового обновления на любом подотрезке эффективно, вместо того чтобы изменять все значений. Как известно из определения несогласованных поддеревьев, в текущий момент времени не в каждой вершине дерева хранится истинное значение, однако когда мы обращаемся к текущему элементу мы работаем с верными данными. Это обеспечивается так называемым "проталкиванием" несогласованности детям (процедура push) при каждом обращений к текущей вершине. При этом после обращения к вершине необходимо пересчитать значение по операций , так как значение в детях могло измениться.А ответ же на запрос по операций
реализуется почти так же, как и в случае без массовых обновлений. Отличие лишь в том, что следует во-первых не забыть раздать детям несогласованность, и во-вторых пересчитать свое значение.Таким образом в обоих запросах очень важно протолкнуть детям несогласованность, вызвать функцию от детей и, наконец, пересчитать значение в текущей вершине.
Псевдокод в общем виде
Пусть поступают запросы двух типов — поиск элемента, соответствующего операций
, и массовое обновление на отрезке относительно операций . Используется классическая реализация дерева отрезка с полуинтервалами.Пусть в узлах дерева хранятся структуры из четырех полей:
- — левая граница полуинтервала, за который "отвечает" текущая вершина.
- — правая граница этого полуинтервала.
- — сумма на отрезке по операций .
- — несогласованность.
// Процедура "проталкивания" несогласованности детям void push(int node) { tree[2 * node + 1].d = tree[2 * node + 1].dtree[node].d; tree[2 * node + 2].d = tree[2 * node + 2].d tree[node].d; tree[node].d = ; // Нейтральный элемент } // Процедура ответа на множественные запросы. void update(int node, int a, int b, int val) { // val - значение, которое поступило в качестве параметра на запрос l = tree[node].left; r = tree[node].right; if [l, r) [a, b) == return; if [l, r) == [a, b) tree[node].d = tree[node].d val; return; push(node); // Вызываем обновление детей update(2 * node + 1, a, b, val); update(2 * node + 2, a, b, val); // Пересчитываем свое значение tree[node].ans = (tree[2 * node + 1].ans tree[2 * node + 1].d) (tree[2 * node + 2].ans tree[2 * node + 2].d); } // Функция ответа на запросы int get_ans(int node, int a, int b) { // node - текущая вершина, a и b - границы запроса l = tree[node].left; r = tree[node].right; if [l, r) [a, b) == return ; if [l, r) == [a, b) return tree[node].ans tree[node].d; push(node); int m = (l + r) / 2; int ans = get_ans (node * 2 + 1, a, ans(b, m)) get_ans (node * 2 + 2, max(a, m), b)); tree[node].ans = (tree[2 * node + 1].ans tree[2 * node + 1].d) (tree[2 * node + 2].ans tree[2 * node + 2].d); return ans; }