Дерево интервалов (interval tree) и пересечение точки с множеством интервалов — различия между версиями
(→Псевдокод) |
|||
| Строка 1: | Строка 1: | ||
| + | {| class="wikitable" align="center" style="color: red; background-color: black; font-size: 56px; width: 800px;" | ||
| + | |+ | ||
| + | |-align="center" | ||
| + | |'''НЕТ ВОЙНЕ''' | ||
| + | |-style="font-size: 16px;" | ||
| + | | | ||
| + | 24 февраля 2022 года российское руководство во главе с Владимиром Путиным развязало агрессивную войну против Украины. В глазах всего мира это военное преступление совершено от лица всей страны, всех россиян. | ||
| + | |||
| + | Будучи гражданами Российской Федерации, мы против своей воли оказались ответственными за нарушение международного права, военное вторжение и массовую гибель людей. Чудовищность совершенного преступления не оставляет возможности промолчать или ограничиться пассивным несогласием. | ||
| + | |||
| + | Мы убеждены в абсолютной ценности человеческой жизни, в незыблемости прав и свобод личности. Режим Путина — угроза этим ценностям. Наша задача — обьединить все силы для сопротивления ей. | ||
| + | |||
| + | Эту войну начали не россияне, а обезумевший диктатор. И наш гражданский долг — сделать всё, чтобы её остановить. | ||
| + | |||
| + | ''Антивоенный комитет России'' | ||
| + | |-style="font-size: 16px;" | ||
| + | |Распространяйте правду о текущих событиях, оберегайте от пропаганды своих друзей и близких. Изменение общественного восприятия войны - ключ к её завершению. | ||
| + | |-style="font-size: 16px;" | ||
| + | |[https://meduza.io/ meduza.io], [https://www.youtube.com/c/popularpolitics/videos Популярная политика], [https://novayagazeta.ru/ Новая газета], [https://zona.media/ zona.media], [https://www.youtube.com/c/MackNack/videos Майкл Наки]. | ||
| + | |} | ||
| + | |||
[[Категория: Вычислительная геометрия]] | [[Категория: Вычислительная геометрия]] | ||
== Определение == | == Определение == | ||
Версия 08:29, 1 сентября 2022
| НЕТ ВОЙНЕ |
|
24 февраля 2022 года российское руководство во главе с Владимиром Путиным развязало агрессивную войну против Украины. В глазах всего мира это военное преступление совершено от лица всей страны, всех россиян. Будучи гражданами Российской Федерации, мы против своей воли оказались ответственными за нарушение международного права, военное вторжение и массовую гибель людей. Чудовищность совершенного преступления не оставляет возможности промолчать или ограничиться пассивным несогласием. Мы убеждены в абсолютной ценности человеческой жизни, в незыблемости прав и свобод личности. Режим Путина — угроза этим ценностям. Наша задача — обьединить все силы для сопротивления ей. Эту войну начали не россияне, а обезумевший диктатор. И наш гражданский долг — сделать всё, чтобы её остановить. Антивоенный комитет России |
| Распространяйте правду о текущих событиях, оберегайте от пропаганды своих друзей и близких. Изменение общественного восприятия войны - ключ к её завершению. |
| meduza.io, Популярная политика, Новая газета, zona.media, Майкл Наки. |
Определение
Дерево интервалов (interval tree) позволяет решать следующую задачу. Дано множество отрезков и множество запросов. Каждый запрос характеризуется точкой . Для каждого запроса необходимо определить множество отрезков из , которые содержат в себе . Построение дерева интервалов занимает время , а также памяти. На каждый запрос дерево интервалов позволяет отвечать за , где — размер ответа на запрос.
Построение
Чтобы построить дерево интервалов сделаем следующее. Найдем медиану множества всех координат отрезков . Это можно сделать за (см. Поиск k-ой порядковой статистики). Далее разделим все отрезки на три группы: те, которые лежат строго слева (справа) от и все остальные. Для первых двух групп рекурсивно построим дерево интервалов. Все остальные отрезки будем хранить в корне дерева. Создадим два списка отрезков, которые пересекают . В одном отсортируем их по левой координате, в другом — по правой.
| Теорема: |
Дерево интервалов имеет глубину . |
| Доказательство: |
| При каждом рекурсивном вызове построения дерева множество концов отрезков уменьшается более чем в два раза. Значит, после рекурсивных вызовов, множество отрезков будет пусто. |
| Теорема: |
Дерево интервалов занимает памяти. |
| Доказательство: |
| По построению каждый отрезок был добавлен ровно в два списка. Вершин в двоичном дереве глубины , очевидно, . |
| Теорема: |
Построение дерева интервалов работает за времени. |
| Доказательство: |
| Отдельно оценим время, которое необходимо для создания всех отсортированных списков отрезков. Т. к. их суммарная длина , требуется времени. Теперь рассмотрим время, необходимое для рекурсивных вызовов. Для каждой вершины дерева это время равно , где — количество отрезков, которые были переданы рекурсивно. Просуммируем это время по всем "слоям" дерева. Под каждым слоем понимаются все вершины дерева, которые лежат на одной и той же глубине. Т. к. в каждом слое множества отрезков для любых двух вершин не пересекаются, то суммарное количество отрезков в слое равно . Слоев всего , значит, имеем общую оценку для построения всего дерева. |
Как отвечать на запрос?
В каждой вершине дерева хранится , ссылки на два поддерева, а также два отсортированных списка отрезков. В вершине хранятся только те отрезки, которые пересекают . Необходимо рассмотреть два симметричных случая. Покажем, что делать в одном из них. Пусть, например, . Тогда в ответ нужно добавить некоторый суффикс отрезков, которые отсортированы по правому концу. Запустимся рекурсивно от правого дерева (т. к. понятно, что никакой отрезок, который хранится в левом поддереве не может содержать ). Аналогично разбирается случай .
| Теорема: |
Ответ на запрос происходит за времени. |
| Доказательство: |
| Глубина дерева равна , значит может быть только рекурсивных вызовов. В каждой вершине ответ происходит за , т. к. может быть просмотрен только один отрезок, который не должен быть добавлен в ответ. |
Псевдокод
struct interval_tree interval_tree *left, *right int x_mid vector<segment> left_segments, right_segments;
interval_tree build_tree(vector<segment> segments)
if (segment.size() == 0)
return NULL
x_mid = mid_element(segments.all_coordinates)
for (segment s : segments)
if (s.right < x_mid)
left_child.add(s);
if (s.left > x_mid)
right_child.add(s);
if (s.left <= x_mid && s.right >= x_mid)
left_segments.add(s);
right_segments.add(s);
sort(left_segments) // by increasing of x_mid - segment.left
sort(right_segments) // by decreasing of segment.right - x_mid
result.left = build(left_child);
result.right = build(right_child);
result.left_segments = left_segments;
result.right_segments = right_segments;
result.x_mid = x_mid;
return result;
vector<segment> get_ans(interval_tree tree, int q_x)
if (tree == NULL)
return empty_result;
if (q_x < tree.x_mid)
result = get_ans(tree.left, q_x);
if (q_x > tree.x_mid)
result = get_ans(tree.right, q_x);
if (q_x < tree.x_mid)
it = left_segments.size() - 1;
while (it != -1 && left_segment[it].left <= q_x)
result.add(left_segments[it--]);
if (q_x >= tree.x_mid)
it = right_segments.size() - 1;
while (it != -1 && right_segments[it].right >= q_x)
result.add(right_segments[it--]);
return result;