Блог пользователя FairyWinx

Автор FairyWinx, 12 месяцев назад, По-русски

Недавно была следующая задача представлена на школьном BSUIR OPEN XIII:

Дан массив целых чисел и запросы изменения в точке. Нужно после каждого такого запроса отвечать в онлайне: сколько существует таких пар $$$i, j$$$, которую дают максимально возможную сумму и находятся на расстоянии не больше $$$k$$$.

Без онлайна — это почти баян с Канадской олимпиады для школьников (решается при помощи DCP-offline), но научимся делать в онлайне. По сути, я хочу научиться делать структуру данных, которая умеет учитывать каждую такую пару ровно один раз. Лично я умею ее делать за $$$log(n)$$$ на запрос.

Давайте дополним дерево отрезков до степени двойки (иначе работать не будет). Тогда у нас будет какое-то количество уровней, и при том, на каждом уровне у нас одиннаковое количество вершин. Тогда для удобство обозначим за $$$l_v, r_v$$$ это отрезок, за который отвечает поддерево, а за $$$lvl_{i, j}$$$ — вершину на $$$i$$$ уровнем под номером $$$j$$$ (у нас вершины на одном уровне идут в порядке возрастания правой границы). Также посчитаем за $$$nxt_v$$$ — самую последнюю вершину на уровне вершины $$$v$$$, для которой выполняется, что $$$r_{nxt} - r_v \leq k$$$ (другими словами, это самая дальняя вершина на уровне, для которой любая пара из этих поддеревьев образует подходящую пару)

Тогда утверждение, достаточно рассмотреть все пары в следующих поддеревьев:

Для каждой вершины $$$v$$$ скажем, что ответ для нее — это максимум ответа из левого/правого поддерева, а также рассмотреть оптимум в парах поддеревьев $$$v, nxt_v$$$, а также $$$v, 'nxt_v$$$, где $$$'nxt_v$$$ — это первая вершина левее на уровне $$$nxt_v$$$. А также взять два оптимума для поддерева размера $$$\leq k$$$.

Теперь как учесть каждую пару ровно один раз — мы не будет мержить две вершины, если у них предки тоже подходят (то есть, максимальное расстояние между парами вершин будет меньше или равно $$$k$$$). А вот этот факт уже очевидный.

Доказательство: проходит стрессы, а значит верно. Так как размеры всех деревьев степени двойки, и при том условие везде одиннаковое, то этот пересчет будет только на одном уровне (когда мы учитываем, что если предки подошли, то эту пару не учитываем). И при том, в этом случае будет задействованы не более $$$3$$$ вершин на этом уровне. (Иначе их предки были бы тоже актуальны). А в этом случае, данный алгоритм действительно каждую пару учтет ровно один раз, так как это будут все актуальные пары. А единственность очевидна, поэтому оставлю ее на доказательство читателя.

Мы научились учитывать каждую пару ровно один раз. Теперь нужно научиться обновлять делать изменение в точке. Давайте заметим, что при изменении вершины ответ поменяется только у предков, а это тривиально делается, а также у вершин, для которых наша была в качестве одного из двух правых. Мы эти вершины можем легко предпосчитать. А поэтому, мы должны пересчитать у них ответ, а затем рекурсивно обновить их родителей. И ввиду того, что нам нужно обновлять еще и родителей, то и получается $$$log^2$$$ (при том достаточно долгий, так как сам код пересчета достаточно тяжелый). (Либо же если аккуратно посмотреть доказательство, то у нас изменятся не так много интересных вершин дерева отрезков и получится $$$log$$$, но ниже предоставлена реализация за $$$log^2$$$)

Реализация
  • Проголосовать: нравится
  • +153
  • Проголосовать: не нравится

»
12 месяцев назад, скрыть # |
 
Проголосовать: нравится +22 Проголосовать: не нравится

getting rid of that negative contribution i see :)

»
12 месяцев назад, скрыть # |
Rev. 2  
Проголосовать: нравится +8 Проголосовать: не нравится

wth is DCP offline?