Если вы действительно хотите изменить массив, вы не сможете добиться большего успеха, чем наивный линейный алгоритм: вам нужно перебрать весь диапазон и соответствующим образом изменить каждый индекс.
Если вы имеете в виду что-то вроде, у вас есть операции обновления, как вы описали, и операция запроса find the sum in the range from x to y
, тогда дерево сегментов может помочь вот так.
Для каждой операции обновления left, right, value
для каждого узла со связанным диапазоном, включенным в [left, right]
, его сумма умножается на value
, поэтому обновите это соответствующим образом и прекратите выполнение рекурсии. Это также будет применяться к интервалам, на которых вы не будете выполнять рекурсию, поэтому вместо фактического обновления суммы сохраните в каждом узле, на сколько был умножен связанный с ним интервал.
При возврате из рекурсии вы можете пересчитать фактические суммы в соответствии с этой информацией.
Псевдокод:
Update(node, left, right, value):
if [left, right] does not intersect node.associated_range:
return
if [left, right] included in node.associated_range:
node.multiplications *= value # 1 initially
return
Update(node.left, left, right, value)
Update(node.right, left, right, value)
node.sum = node.left.sum * node.left.multiplications +
node.right.sum * node.right.multiplications
По сути, каждый узел будет хранить свою сумму, учитывая только умножения в дочерних сегментах. Его истинная сумма будет лениво вычисляться во время запроса с использованием информации об умножениях, которые повлияли на этот интервал.
Затем запрос суммы выполняется почти как обычный запрос к дереву отрезков: только обязательно умножайте суммы на то, на сколько они или родительские интервалы были умножены.
Псевдокод:
Query(node, multiplications = 1, left, right):
if [left, right] does not intersect node.associated_range:
return 0
if [left, right] included in node.associated_range:
return node.sum * multiplications
return Query(node.left, multiplications * node.multiplications, left, right) +
Query(node.right, multiplications * node.multiplications, left, right)
Функция, которая первоначально строит дерево, оставлена в качестве упражнения (вы можете сделать немного лучше, чем вызывать update n
раз).
person
IVlad
schedule
05.07.2015