<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.118.78.97&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.118.78.97&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/217.118.78.97"/>
		<updated>2026-06-11T09:41:58Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%BE%D0%B2_(interval_tree)_%D0%B8_%D0%BF%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D1%81_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE%D0%BC_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%BE%D0%B2&amp;diff=36181</id>
		<title>Дерево интервалов (interval tree) и пересечение точки с множеством интервалов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%BE%D0%B2_(interval_tree)_%D0%B8_%D0%BF%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D1%81_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE%D0%BC_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B2%D0%B0%D0%BB%D0%BE%D0%B2&amp;diff=36181"/>
				<updated>2014-02-22T10:49:27Z</updated>
		
		<summary type="html">&lt;p&gt;217.118.78.97: /* Псевдокод */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Категория: Вычислительная геометрия]]&lt;br /&gt;
== Определение ==&lt;br /&gt;
Дерево интервалов (interval tree) позволяет решать следующую задачу. Дано множество отрезков &amp;lt;tex&amp;gt;I=\{[x_1, x'_1], \ldots, [x_n, x'_n]\}&amp;lt;/tex&amp;gt; и множество запросов. Каждый запрос характеризуется точкой &amp;lt;tex&amp;gt;q_x&amp;lt;/tex&amp;gt;. Для каждого запроса необходимо определить множество отрезков из &amp;lt;tex&amp;gt;I&amp;lt;/tex&amp;gt;, которые содержат в себе &amp;lt;tex&amp;gt;q_x&amp;lt;/tex&amp;gt;. Построение дерева интервалов занимает время &amp;lt;tex&amp;gt;O(n \log\,n)&amp;lt;/tex&amp;gt;, а также &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти. На каждый запрос дерево интервалов позволяет отвечать за &amp;lt;tex&amp;gt;O(\log\,n + k)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; {{---}} размер ответа на запрос.&lt;br /&gt;
== Построение ==&lt;br /&gt;
Чтобы построить дерево интервалов сделаем следующее. Найдем медиану множества всех координат отрезков &amp;lt;tex&amp;gt;x_{mid}&amp;lt;/tex&amp;gt;. Это можно сделать за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; (см. [[Поиск k-ой порядковой статистики за линейное_время | Поиск k-ой порядковой статистики]]). Далее разделим все отрезки на три группы: те, которые лежат строго слева (справа) от &amp;lt;tex&amp;gt;x_{mid}&amp;lt;/tex&amp;gt; и все остальные. Для первых двух групп рекурсивно построим дерево интервалов. Все остальные отрезки будем хранить в корне дерева. Создадим два списка отрезков, которые пересекают &amp;lt;tex&amp;gt;x_{mid}&amp;lt;/tex&amp;gt;. В одном отсортируем их по левой координате, в другом {{---}} по правой.&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Дерево интервалов имеет глубину &amp;lt;tex&amp;gt;O(\log\,n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
При каждом рекурсивном вызове построения дерева множество концов отрезков уменьшается более чем в два раза. Значит, после &amp;lt;tex&amp;gt;O(\log\,n)&amp;lt;/tex&amp;gt; рекурсивных вызовов, множество отрезков будет пусто.&lt;br /&gt;
}}&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Дерево интервалов занимает &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
|proof=&lt;br /&gt;
По построению каждый отрезок был добавлен ровно в два списка. Вершин в двоичном дереве глубины &amp;lt;tex&amp;gt;O(\log\,n)&amp;lt;/tex&amp;gt;, очевидно, &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Построение дерева интервалов работает за &amp;lt;tex&amp;gt;O(n\log\,n)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
|proof=&lt;br /&gt;
Отдельно оценим время, которое необходимо для создания всех отсортированных списков отрезков. Т. к. их суммарная длина &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;, требуется &amp;lt;tex&amp;gt;O(n\log\,n)&amp;lt;/tex&amp;gt; времени. Теперь рассмотрим время, необходимое для рекурсивных вызовов. Для каждой вершины дерева это время равно &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; {{---}} количество отрезков, которые были переданы рекурсивно. Просуммируем это время по всем &amp;lt;tex&amp;gt;O(\log\,n)&amp;lt;/tex&amp;gt; &amp;quot;слоям&amp;quot; дерева. Под каждым слоем понимаются все вершины дерева, которые лежат на одной и той же глубине. Т. к. в каждом слое множества отрезков для любых двух вершин не пересекаются, то суммарное количество отрезков в слое равно &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Слоев всего &amp;lt;tex&amp;gt;O(\log\,n)&amp;lt;/tex&amp;gt;, значит, имеем общую оценку &amp;lt;tex&amp;gt;O(n\log\,n)&amp;lt;/tex&amp;gt; для построения всего дерева.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Как отвечать на запрос? == &lt;br /&gt;
В каждой вершине дерева хранится &amp;lt;tex&amp;gt;x_{mid}&amp;lt;/tex&amp;gt;, ссылки на два поддерева, а также два отсортированных списка отрезков. В вершине хранятся только те отрезки, которые пересекают &amp;lt;tex&amp;gt;x_{mid}&amp;lt;/tex&amp;gt;.  Необходимо рассмотреть два симметричных случая. Покажем, что делать в одном из них. Пусть, например, &amp;lt;tex&amp;gt;q_x&amp;gt;x_{mid}&amp;lt;/tex&amp;gt;. Тогда в ответ нужно добавить некоторый суффикс отрезков, которые отсортированы по правому концу. Запустимся рекурсивно от правого дерева (т. к. понятно, что никакой отрезок, который хранится в левом поддереве не может содержать &amp;lt;tex&amp;gt;q_x&amp;lt;/tex&amp;gt;). Аналогично разбирается случай &amp;lt;tex&amp;gt;q_x &amp;lt; x_{mid}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Ответ на запрос происходит за &amp;lt;tex&amp;gt;O(\log\,n + answer)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
|proof=&lt;br /&gt;
Глубина дерева равна &amp;lt;tex&amp;gt;O(\log\,n)&amp;lt;/tex&amp;gt;, значит может быть только &amp;lt;tex&amp;gt;O(\log\,n)&amp;lt;/tex&amp;gt; рекурсивных вызовов. В каждой вершине ответ происходит за &amp;lt;tex&amp;gt;O(answer)&amp;lt;/tex&amp;gt;, т. к. может быть просмотрен только один отрезок, который не должен быть добавлен в ответ.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Псевдокод == &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  struct interval_tree&lt;br /&gt;
    interval_tree *left, *right&lt;br /&gt;
    int x_mid&lt;br /&gt;
    vector&amp;lt;segment&amp;gt; left_segments, right_segments;&lt;br /&gt;
&lt;br /&gt;
  interval_tree build_tree(vector&amp;lt;segment&amp;gt; segments)&lt;br /&gt;
    if (segment.size() == 0)&lt;br /&gt;
      return NULL&lt;br /&gt;
    x_mid = mid_element(segments.all_coordinates)&lt;br /&gt;
    for (segment s : segments)&lt;br /&gt;
      if (s.right &amp;lt; x_mid)&lt;br /&gt;
        left_child.add(s);&lt;br /&gt;
      if (s.left &amp;gt; x_mid)&lt;br /&gt;
        right_child.add(s);&lt;br /&gt;
      if (s.left &amp;lt;= x_mid &amp;amp;&amp;amp; s.right &amp;gt;= x_mid)&lt;br /&gt;
        left_segments.add(s);&lt;br /&gt;
        right_segments.add(s);&lt;br /&gt;
    sort(left_segments) // by increasing of x_mid - segment.left&lt;br /&gt;
    sort(right_segments) // by decreasing of segment.right - x_mid&lt;br /&gt;
    result.left = build(left_child);&lt;br /&gt;
    result.right = build(right_child);&lt;br /&gt;
    result.left_segments = left_segments;&lt;br /&gt;
    result.right_segments = right_segments;&lt;br /&gt;
    result.x_mid = x_mid;&lt;br /&gt;
    return result;&lt;br /&gt;
&lt;br /&gt;
  vector&amp;lt;segment&amp;gt; get_ans(interval_tree tree, int q_x) &lt;br /&gt;
    if (tree == NULL)&lt;br /&gt;
      return empty_result;&lt;br /&gt;
    if (q_x &amp;lt; tree.x_mid)&lt;br /&gt;
      result = get_ans(tree.left, q_x);&lt;br /&gt;
    if (q_x &amp;gt; tree.x_mid)&lt;br /&gt;
      result = get_ans(tree.right, q_x);&lt;br /&gt;
    if (q_x &amp;lt; tree.x_mid)&lt;br /&gt;
      it = left_segments.size() - 1;&lt;br /&gt;
      while (it != -1 &amp;amp;&amp;amp; left_segment[it].left &amp;lt;= q_x)&lt;br /&gt;
        result.add(left_segments[it--]);&lt;br /&gt;
    if (q_x &amp;gt;= tree.x_mid)&lt;br /&gt;
      it = right_segments.size() - 1;&lt;br /&gt;
      while (it != -1 &amp;amp;&amp;amp; right_segments[it].right &amp;gt;= q_x)&lt;br /&gt;
        result.add(right_segments[it--]);&lt;br /&gt;
    return result;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>217.118.78.97</name></author>	</entry>

	</feed>