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

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

Всем привет!

На контестах периодически попадаются задачи на запросы на отрезках. Большая часть задач даёт запросы в оффлайне, что даёт большую свободу действий, но всё же часто они сводятся к дереву отрезков, а иногда и алгоритму Мо. Однако иногда в задачах может оказаться так, что оффлайн её решает простой Мо, а в онлайне она становится интересной. В таких ситуациях некоторые люди пытаются поддерживать что-то типа $$$500$$$ разных состояний алгоритма Мо, я вообще не понимал, что имеется в виду.

Сегодня же я сумел придумать версию онлайн Мо, работающую за $$$O(n^{\frac{5}{3}})$$$ времени и памяти в нормальных задачах (в которых движение границ делается за $$$O(1)$$$). Для анализа асимптотики я буду считать, что $$$n = q$$$. Я не первый, кто такую идею придумал. Как оказалось, здесь и здесь было обсуждение, где такая идея была предложена, но я хочу сам о ней рассказать, потому что я о ней раньше не знал.

В этом блоге я хочу разобрать, как с помощью онлайн Мо можно решить задачу с недавнего Educational раунда.

2043G - Задача на запросы

Тут слишком много всего наворочено — запросы изменения, да ещё и закодированы. Попробуем сначала решить версию оффлайн и без запросов обновления. Стоит оговориться, что я буду считать не количество индексов $$$i \lt j$$$ таких, что $$$a_i \neq a_j$$$, а наоборот, что $$$a_i = a_j$$$. Из этой величины легко получить ответ на исходную задачу, однако количество пар индексов с равными значениями поддерживать несколько проще.

Сама задача — несложное упражнение на алгоритм Мо.

Для тех, кому интересна реализация

Я хочу взглянуть на анализ асимптотики с геометрической стороны. Размер блока для алгоритма Мо обозначим за $$$B \approx \sqrt{n}$$$. Вкратце, мы делим плоскость на квадратики со стороной $$$B$$$ и обходим квадратики в правильном порядке.

Анализ асимптотики

Теперь добавим ограничение в виде онлайн запросов. К сожалению в этой версии мы не можем выбирать порядок обхода квадратиков, да и в каждый квадратик нам может понадобиться заходить несколько раз, поэтому нужен другой подход. Понятно, что лишь одной парой указателей нам не обойтись, поскольку в таком случае на каждый запрос мы будем отвечать за $$$O(n)$$$, что долго. Назовём состоянием всю необходимую информацию, которую мы обычно поддерживаем для одного отрезка. В данном случае это массив количеств $$$cnt$$$, количество пар равных индексов $$$sum$$$ и указатели $$$L$$$ и $$$R$$$. Я хочу создать несколько состояний, чтобы от какого-то из них можно было быстро дойти до нашего запроса.

Выберем $$$B \approx n^{\frac{2}{3}}$$$. Теперь у нас мало квадратиков, всего $$$\frac{n^2}{B^2} = n^{\frac{2}{3}}$$$. Я хочу сделать так, чтобы в каждом квадратике было состояние, чтобы от него было недалеко идти до очередного запроса. Действительно, внутри квадратика расстояние между точками не превосходит $$$2B$$$, а это уже приемлемое время работы для запроса. Алгоритм можно описать так:

Определим квадратик, в котором находится запрос.

  • Если в нём ранее не было запросов, то можно за $$$O(n)$$$ инициализировать этот блок. Создадим состояние, например, в точке самого запроса.
  • Иначе у нас есть состояние на расстоянии не более $$$2B$$$, поэтому мы можем за $$$O(B)$$$ ответить на запрос.

Так как блоков мало, суммарно все инициализации отработают за $$$O(n^{\frac{5}{3}})$$$, а суммарное количество движений указателей не превосходит $$$O(qB) = O(nB) = O(n^{\frac{5}{3}})$$$.

Отлично, мы научились делать Мо в онлайне быстрее чем за $$$O(nq)$$$. А можно ли прикрутить запросы изменения? И если да, то надо ли нам чем-либо жертвовать? Оказывается, ответы на эти вопросы — да и нет! Обычно при запросах изменения используется 3D Мо, который вводит время в качестве третьего измерения, и обходится уже не плоскость, а трёхмерное пространство. Тогда чтобы двигать третий параметр $$$T$$$, нужно проверить, лежит ли изменяемая позиция в текущем состоянии, и если да, то сделать del и add. Но нам ведь ничего не мешает сделать то же самое, просто для всех блоков. Поскольку их, опять же, мало, $$$O(n^{\frac{2}{3}})$$$, время работы никак не ухудшается.

С помощью такой идеи понятно, как развалить задачу. Да и пишется это довольно легко.

Моё решение: 329249141

Это просто феноменально, имхо, что настолько простая идея, как алгоритм Мо, может работать в онлайне, да ещё и с изменениями!

P. S.: Правда, как оказалось, это некоторая интерпретация разбора задачи, а не другое решение. Разбиение на квадратики — то же самое, что и разбиение на блоки. Инициализация состояния в каждом квадратике эквивалентна предпосчёту ответа для каждой пары блоков, а движение указателей — добавление элементов с краёв неполных блоков.

  • Проголосовать: нравится
  • +33
  • Проголосовать: не нравится

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

Auto comment: topic has been updated by Noobish_Monk (previous revision, new revision, compare).

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

Seems useful and interesting

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

Online Mo in general could potentially be done in same complexity or $$$O(n^{3/2})$$$ if you only need to store a single number.

It is only in this problem where you truly need to remember n things, that you need $$$O(n^{5/3})$$$ for online version. Alternatively you can do $$$O(n^{3/2} log n)$$$ using persistence. This is practically worse but conceptually obvious.

Mo with updates are known to be done in O(n^{5/3}), this exists independently of online thing.

I do not believe you have meaningfully illustrated the dependency of knowledge (and the novelty/choice) that is demonstrated in this approach. It reads like you copied an editorial without giving any more insight than what is already present in this one problem. You are overfitting explanations on this one solution. (It is also difficult to filter out which part of what you said is new/uncommon, and what isn’t).

Put it another way, you didn’t really explain how to do online mo adequately. You should have just titled it a solution to this problem. I know maybe this is your aim all along, but I just want to say I learnt something from the blog while but am unhappy because I didn’t get what I expected.

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

    Just be happy for learning something...

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

    After some discussion with my friend I understood, that this in indeed the editorial of the problem from another perspective. When the idea of Mo online came to me, I wasn't thinking about this problem, it was in another order:) I also checked the editorial only briefly, as I found it somewhat complicated and Mo wasn't mentioned, so I believed that I had another idea while it was equivalent to the author's solution. I slightly changed the blog, hopefully it is better now.

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

My friend ctzm has a similar thing : https://www.luogu.com.cn/article/udf5jzd5

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

I think this approach is vulnerable to getting hacked in contest, especially if you use a fixed block size. I remember in that round I solved the problem this way, then hacked everyone else who solved it this way, and then got hacked myself.

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

My friend have similar blog https://codeforces.me/blog/entry/137774