Пытаюсь объяснить более интуитивно (как я понял). Я разделю его на четыре этапа:
Предположим, что обновление находится между A и B с V, а запрос является префиксным запросом для любого индекса ‹=X
Дерево запроса обновления/точки первого диапазона (T1)
Первый — это простое дерево запроса обновления/точки диапазона. Когда вы обновляете A до B с помощью V, на практике вы добавляете V в позицию A, поэтому это влияет на любой префиксный запрос X›=A. Затем вы удаляете V из B+1, так что любой запрос X ›= B+1 не увидит, что V добавлено к A. Никаких сюрпризов здесь нет.
Префиксный запрос к дереву обновлений/точек диапазона
T1.sum(X)
— это точечный запрос к этому первому дереву в точке X. Тогда мы оптимистично предполагаем, что каждый элемент перед X равен значению в точке X. Вот почему мы делаем T1.sum(X)*X
. Очевидно, это не совсем правильно, поэтому мы:
Используйте измененное дерево запроса обновления/точки диапазона, чтобы исправить результат (T2)
При обновлении диапазона мы также обновляем второе дерево, чтобы сообщить, сколько нам нужно исправить первый запрос T1.sum(X)*X
. Это обновление состоит в удалении (A-1)*V
из любого запроса X›=A. Затем мы добавляем обратно B*V
для X›=B. Мы делаем последнее, потому что запросы к первому дереву не вернут V для X›=B+1 (из-за T1.add(B+1, -V)
), поэтому нам нужно как-то сказать, что существует прямоугольник площади (B-A+1)*V
для любого запроса X›=B +1. Мы уже удалили (A-1)*V
из A, нам нужно только добавить обратно B*V
в B+1.
Обернув все это вместе
update(A, B, V):
T1.add(A, V) # add V to any X>=A
T1.add(B+1, -V) # cancel previously added V from any X>=B+1
T2.add(A, (A-1)*V) # add a fix for (A-1)s V that didn't exist before A
T2.add(B+1, -B*V) # remove the fix, and add more (B-A+1)*V to any query
# X>=B+1. This is really -(A-1)*V -(B-A+1)*V, but it
# simplifies to -B*V
sum(X):
return T1.sum(X)*X - T2.sum(X)
person
Juan Lopes
schedule
10.01.2015