EduBrick
← вернуться к уроку · Уровень профи: проверь себя

L. Различные на отрезке

1000 мс · 256 МБ · всё или ничего

Дан массив. На каждый запрос (l,r)(l, r) нужно сказать, сколько различных значений встречается среди al,,ara_l, \ldots, a_r.

Обновлений нет, все запросы известны заранее - значит, можно отвечать на них не в том порядке, в котором они заданы. Это и есть алгоритм Мо.

Два указателя, которые не откатываются

Держим текущий отрезок [l,r][l, r] и счётчики cnt[v] - сколько раз значение vv встречается внутри. Отдельно храним число различных: при cnt[v]++ с нуля до единицы оно растёт, при cnt[v]-- до нуля - падает.

auto add = [&](int i) { if (cnt[a[i]]++ == 0) distinct++; };
auto del = [&](int i) { if (--cnt[a[i]] == 0) distinct--; };

Переход от одного запроса к другому стоит столько, на сколько сдвинулись указатели. Если запросы идут в произвольном порядке, суммарный сдвиг может быть квадратичным.

Порядок, в котором сдвиги малы

Разобьём индексы на блоки длины BB и отсортируем запросы по паре (блок левого конца, правый конец).

  • внутри блока левый конец гуляет по блоку: O(B)O(B) на запрос, всего O(qB)O(qB);
  • внутри блока правый конец только растёт: O(n)O(n) на блок, всего O(n2/B)O(n^2 / B).

При B=n/qB = n / \sqrt{q} обе суммы равны O(nq)O(n\sqrt{q}). Обычная корневая B=nB = \sqrt{n} тоже проходит.

Змейка

В чётных блоках сортируем по правому концу по возрастанию, в нечётных - по убыванию. Тогда при переходе к следующему блоку правый указатель не откатывается в начало. Это не меняет асимптотику, но на практике ускоряет примерно в полтора раза.

Подробнее: «Алгоритм Мо».

Формат ввода

В первой строке - число nn (1n1051 \le n \le 10^5).

Во второй строке - nn чисел aia_i (1ai1061 \le a_i \le 10^6).

В третьей строке - число запросов qq (1q1051 \le q \le 10^5).

В следующих qq строках - пары ll и rr (1lrn1 \le l \le r \le n).

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

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

Примеры

ввод
5
1 2 1 3 2
4
1 5
1 3
2 4
3 3
вывод
3
2
3
1
ввод
6
4 4 4 4 4 4
3
1 6
2 3
5 5
вывод
1
1
1
Войдите, чтобы отправлять решения.
← Вернуться к уроку