Вы находитесь на странице: 1из 4

Сканирующая прямая

Общая идея
Есть n объектов с какими-то свойствами v1, v2 .. vn. Упорядочим их по какому-то из
свойств в правильном порядке, чтобы не делать лишние операции.

Задача 1
Дано n отрезков на числовой прямой и m точек запроса на этой же прямой. Для каждой из
данных точек определите, скольким отрезкам они принадлежат. Точка x считается
принадлежащей отрезку с концами a и b , если выполняется двойное неравенство min(a,
b) ≤ x ≤ max(a , b). Для каждой точки найти количество отрезков, в которых она
содержится.

Решение

Разобьем каждый отрезок на 2 точки: начало и конец отрезка. Отсортируем 2 * n + m


точек по координате так, что при равенстве координат выполняются следующие
инварианты: начала отрезков идут раньше других точек, концы отрезков идут позже
других точек.

Пройдемся по этим точкам в данном отсортированнам порядке. Заведем счетчик,


который условно будем называть в дальнейшем “баланс”. Изначально баланс равен
нулю, при встрече точки начала отрезка, будем увеличивать баланс на 1, при встречи
конца отрезка - уменьшать на 1.

Таким образом, в тот момент, когда мы будем находиться в какой-то точке запроса,
баланс будет в точности равняться количеству открытых отрезков, те количеству
отрезков, которым принадлежит данная точка. Итоговая асимптотика O(N log N) (из-за
сортировки!!!, точки перебираем за линейное время).
Задача 2
На числовой прямой окрасили N отрезков. Известны координаты левого и
правого концов каждого отрезка (Li и Ri). Найти длину окрашенной части
числовой прямой.

Решение

Идея ровно такая же, как и в предыдущей задаче. Заметим, что теперь все наши точки
начала и концов отрезков разбивают нашу числовую прямую на 2 луча, которые точно
не покрашены, и на 2 * n - 1 непересекающихся отрезков(возможно часть из них
нулевой длины). Тогда покрашены будут лишь те отрезки, внутри которых баланс не
равен нулю. Значит, снова за O(N log N) мы решили задачу.
Задача 3
На прямой задано некоторое множество отрезков с целочисленными
координатами концов [Li, Ri]. Выберите среди данного множества подмножество
отрезков, целиком покрывающее отрезок [0, M], (M — натуральное число),
содержащее наименьшее число отрезков.

Решение
Здесь нам потребуется уже немного другая идея. Отрезки не придется
разбивать на 2 точки. Отсортируем отрезки по началу. Посмотрим какой
должен быть самый левый отрезок из ответа. Во-первых, его начало должно
лежать левее 0. Среди всех таких отрезков, заметим, что выгоднее всего
взять отрезок с наибольшей координатой правого конца. Это идея жадного
алгоритма. Почему так? Допустим, что есть смысл взять какой-то отрезок с
меньшей координатой правого конца, но тогда если мы заменим этот отрезок
на отрезок с большей правой координатой, то так же это останется ответом!

Пусть теперь нам надо покрыть отрезок [R1, M]. Снова поступим так, как при
выборе первого отрезка.

Будем повторять эту операцию до тех пор, пока Ri < M. Итого, O(N log N)
Объединение прямоугольников
Найти площадь объединения прямоугольников со сторонами параллельными
осям координат.

Решение
Важная задача, которую можно решить с помощью применения сканирующей
прямой за O(N ^ 2), а при использовании одной структуры данных решение
за квадрат можно оптимизировать до O(N * log N). Давайте разобьем
прямоугольники на 2 отрезка: левую и правую грань. Отсортируем эти
отрезки по координате x. Будем поддерживать “открытые прямоугольники”,
подобно как мы поддерживали открытые отрезки. Теперь перебираем в
нашем порядке отрезки. Пусть между текущим и предыдущим отрезком
расстояние h. Найдем объединение открытых отрезков по оси y - w. Тогда
площадь объединения прямоугольников между этими соседними отрезками
будет w * h. Теперь в зависимости от типа отрезка, в котором мы находимся,
закроем или откроем прямоугольник. Проще, чем казалось, неправда ли?

Вам также может понравиться