Конвейер и отчёт по первым секциям

тема: Fenwick/Segment tree · уровень: продвинутый

Условие

На заводе стоит длинный конвейер из n секций, пронумерованных от 1 до n. В каждой секции лежит некоторое число деталей (оно может быть отрицательным — например, если по учёту есть долг).

Диспетчер делает два типа действий:

Твоя задача — быстро отвечать на такие запросы.

Формат ввода

В первой строке заданы два целых числа n и q — количество секций и количество действий. Во второй строке задано n целых чисел a1, a2, ..., an — начальные значения по секциям. Далее идут q строк, каждая описывает одно действие одного из видов:

Формат вывода

Для каждого запроса вида SUM r выведи одно целое число в отдельной строке.

Ограничения

Пример

Ввод:

5 6
3 -2 5 0 4
SUM 3
ADD 2 10
SUM 2
ADD 5 -7
SUM 5
SUM 1

Вывод:

6
11
13
3

Как решать — идея подхода

Приём: Дерево Фенвика

Если после каждого ADD пересчитывать все обычные префиксные суммы, придётся менять значения от позиции i до n. Это до n действий на один запрос, а при 65000 операциях может быть слишком долго.

Здесь подходит дерево Фенвика (Binary Indexed Tree). Это массив bit, где ячейка с номером i хранит сумму некоторого блока, оканчивающегося в i. Размер блока определяется последним установленным битом числа i:

lowbit(i) = i & -i

Например, bit[6] отвечает за блок из 2 позиций, а bit[8] — за блок из 8 позиций. Благодаря этому любой префикс можно разбить всего на несколько таких блоков.

План решения:

Обе операции делают не более O(log n) шагов, поэтому общее время — O((n + q) log n), память — O(n).

Частая ошибка — использовать индексацию с нуля. Формула i & -i и переходы дерева рассчитаны на позиции от 1; индекс 0 в цикле обновления приведёт к бесконечному циклу.

Решить задачу с автопроверкой на Python →

Куда дальше