Блог пользователя re-wa-tl-ok

Автор re-wa-tl-ok, история, 13 месяцев назад, По-русски
Задача 1:
Задача 2:

Офлайн обе задачи можно решить с помощью алгоритма Мо и 3DMo (существуют и другие способы, такие как scanline и т. д.), но есть задачи, в которых необходимо отвечать на запросы в онлайн-режиме. Решение с персистентным деревом отрезков, которое я слышал от Andrew-13, неплохое, но оно не поддерживает запросы на обновление. Итак, давайте разберёмся, как решить обе задачи.

Задача 1: $$$O(log(n)^2)$$$ на запрос с использованием 2D Неявного Дерева Отрезков

Что такое "уникальный" элемент на подотрезке? — элемент в подотрезке $$$a[ l, r ]$$$ считается уникальным, если он встречается ровно один раз в этом диапазоне, то есть его предыдущее вхождение (если оно есть) находится перед $$$l$$$, а следующее (если оно есть) — после $$$r$$$.

Введём определение: ссылка элемента $$$a_i$$$ — это указатель на ближайший равный ему элемент слева или справа. Если таких элементов нет, левая ссылка указывает на $$$-1$$$, а правая — на $$$n$$$.

Теперь нам нужно найти количество элементов на отрезке $$$[ l, r ]$$$, таких что их левая ссылка указывает на позицию < $$$l$$$, а правая — на позицию > $$$r$$$. Для этого построим массивы $$$future$$$ и $$$last$$$, содержащие ссылки на ближайшие равные элементы:

$$$future_i$$$ содержит индекс ближайшего элемента, равного $$$a_i$$$ справа (или $$$n$$$, если такого элемента нет).

$$$last_i$$$ содержит индекс ближайшего элемента, равного $$$a_i$$$ слева (или $$$-1$$$, если такого элемента нет).

Рассмотрим текущий запрос: $$$[ l, r ]$$$. Посчитаем количество элементов, у которых $$$future_i$$$ > $$$r$$$ и $$$last_i$$$ < $$$l$$$. Теперь все координаты положительны, так как $$$l$$$, $$$last_i$$$ < $$$n$$$ < $$$10^5$$$.

Таким образом, нам нужно посчитать количество точек ($$$x_i$$$, $$$y_i$$$) = ($$$1000000$$$ — $$$last_i$$$, $$$future_i$$$), которые находятся в верхней правой части плоскости относительно ($$$minX$$$, $$$minY$$$) = ($$$1000000$$$ — $$$l$$$, $$$r$$$). 2D Неявное Дерево Отрезков позволяет сделать это за $$$O(log(n)^2)$$$.

Это было бы решением, если бы не существовали точки:

  1. которые находятся перед левой границей, а их правая ссылка пересекает правую границу.

  2. которые находятся после правой границы, а их левая ссылка пересекает левую границу.

Поэтому нам нужно вычислить количество ненужных точек и вычесть их из общего ответа. Это можно реализовать с помощью простого Дерева Отрезков с Декартовыми Деревьями в узлах, так как нам нужно уметь отвечать на 2 запроса:

  1. посчитать количество элементов на отрезке [ $$$0$$$, $$$l$$$ — $$$1$$$ ], у которых правая ссылка > $$$r$$$.

  2. посчитать количество элементов на отрезке [ $$$r$$$ + $$$1$$$, $$$n$$$ — $$$1$$$ ], у которых левая ссылка < $$$l$$$.

Итог: Предподсчёт ~ $$$O(n * log(n)^2)$$$ Ответ на запрос ~ $$$O(log(n)^2)$$$.

Код
Задача 2: $$$O(log(n)^2)$$$ на запрос с использованием 2D Неявного Дерева Отрезков

Что насчёт запросов на обновление? Заметим, что мы также можем легко отвечать на них за $$$O(log(n)^2)$$$. Обозначим:

$$$L$$$ — максимальная позиция в $$$a$$$, меньшая $$$i$$$, такая что $$$a_L$$$ = $$$X$$$; $$$F$$$ — минимальная позиция в $$$a$$$, большая $$$i$$$, такая что $$$a_F$$$ = $$$X$$$, где $$$X$$$ — это элемент в запросе на обновление. Если таких элементов нет, просто установим: $$$L$$$ = $$$-1$$$, $$$F$$$ = $$$n$$$.

При обновлении элемента $$$a_i$$$ изменяются только ссылки:

  1. $$$a[i]$$$

  2. $$$a[last_i]$$$

  3. $$$a[future_i]$$$

  4. $$$a[L]$$$

  5. $$$a[F]$$$

Остаётся не забыть обновить Дерево Отрезков с Декартовыми Деревьями и точки на 2D плоскости Дерева Отрезков.

Итог: Предподсчёт ~ $$$O(n * log(n)^2)$$$ Ответ на запрос ~ $$$O(log(n)^2)$$$.

Код

Моё решение можно найти здесь.

Полный текст и комментарии »

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