<?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=Pashkal</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=Pashkal"/>
		<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/Pashkal"/>
		<updated>2026-06-11T13:24:11Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=20272</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=20272"/>
				<updated>2012-04-04T17:38:06Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: Не трогайте цитату в начале!!!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента, изменить элемент по номеру и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope''' (''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;: '''количество вершин в поддереве нашей вершины'''(в поддерево включается и сама вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: '''split''' {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и '''merge''' {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и слияние двух любых деревьев.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура '''split''' запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин. Также известно, что в левом поддереве вершины находится &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; вершин, а в правом &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;. Рассмотрим сначала два тривиальных случая. Первый: &amp;lt;tex&amp;gt;l = t&amp;lt;/tex&amp;gt;. В этом случае процедура '''split''' должна просто пометить, что у корня больше нет левого сына, и вернуть его бывшего левого сына в качестве левого ответа, а сам корень {{---}} в качестве правого. Второй случай (&amp;lt;tex&amp;gt;t = l + 1&amp;lt;/tex&amp;gt;) рассматривается аналогично. Следующий случай не так тривиален: &amp;lt;tex&amp;gt;t &amp;lt; l&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру '''split''' от левого сына с тем же параметром &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, и левая часть сына станет левым ответом нашей процедуры, а правая часть станет левым сыном корня, после чего корень станет правым ответом. Случай &amp;lt;tex&amp;gt;t &amp;gt; l + 1&amp;lt;/tex&amp;gt; рассматривается аналогично, с той лишь разницей, что от правого сына отрезается &amp;lt;tex&amp;gt;t - l - 1&amp;lt;/tex&amp;gt; вершин.&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из реализаций процедуры '''merge'''. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры '''merge''' для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности значений &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих значений заключается в том, что после любого действия с детьми вершины нужно записать в ее поле &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; сумму этих значений в ее новых детях, увеличенную на единицу.&lt;br /&gt;
&lt;br /&gt;
==Применение описанного дерева==&lt;br /&gt;
Что же мы получили? У нас есть структура, от которой можно отрезать слева кусок произвольной длины и слить два любых куска в один в нужном порядке. Теперь мы можем:&lt;br /&gt;
* вставить элемент в любое место (отрежем нужное количество слева, сольем левое дерево с деревом из одного добавленного элемента и результат {{---}} с правым деревом)&lt;br /&gt;
* переставить любой кусок массива куда угодно (сделаем нужные разрезы и слияния в правильном порядке)&lt;br /&gt;
* совершать групповые операции с элементами. Вспомним реализацию таких операций в дереве отрезков и поймем, что ничего не помешает нам сделать то же самое с описанным деревом. В групповые операции включается, естественно, и взятие функции от отрезка.&lt;br /&gt;
* сделав на одном исходном массиве два дерева из элементов разной четности, можно решить задачу про смену мест четных и нечетных на отрезке (одно из домашних заданий)&lt;br /&gt;
* повелевать миром&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=14170</id>
		<title>Алгоритм Бентли-Оттмана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=14170"/>
				<updated>2011-12-09T04:00:45Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: /* Сканирующая точка */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Бентли-Оттмана(англ. Bentley-Ottmann) - алгоритм, позволяющий по множеству отрезков на плоскости получить множество точек, в которых эти отрезки пересекаются, при этом для каждой точки алгоритм выдает множество отрезков, пересекающихся в ней.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
[[Файл:pic1.jpg|right|560|thumb|Пример результата работы алгоритма]]&lt;br /&gt;
На плоскости лежит &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; отрезков, каждый из них задан координатами своих концов. Требуется по этим данным определить множество точек, в которых эти отрезки пересекаются. Однако, не всегда координаты точки можно абсолютно точно представить с помощью вещественных типов данных. Поэтому характеризовать каждую точку будем множеством отрезков, которые пересекаются в этой точке.&lt;br /&gt;
&lt;br /&gt;
Для упрощения понимания введем два ограничения на входные данные:&lt;br /&gt;
* не существует вертикальных отрезков&lt;br /&gt;
* не существует пары отрезков, имеющих более одной общей точки&lt;br /&gt;
* никакие три отрезка не пересекаются в одной точке&lt;br /&gt;
&lt;br /&gt;
Как обрабатывать эти случаи будет объяснено позднее.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
===Основная идея===&lt;br /&gt;
Алгоритм будет основан на идее сканирующей прямой. Опишем три типа событий, которые мы и будем обрабатывать:&lt;br /&gt;
* начался новый отрезок&lt;br /&gt;
* два отрезка пересеклись&lt;br /&gt;
* отрезок закончился&lt;br /&gt;
&lt;br /&gt;
Сканирующая прямая будет расположена параллельно оси ординат, и двигаться вдоль оси абсцисс в сторону ее положительного направления. Учитывая введенные ограничения на входные данные, прямая никогда не будет проходить через два события одновременно.&lt;br /&gt;
&lt;br /&gt;
===Статус===&lt;br /&gt;
[[Файл:pic2.jpg|right|560|thumb|Иллюстрация определения статуса]]&lt;br /&gt;
Назовем статусом множество, в которой содержатся все отрезки, пересекающие нашу сканирующую прямую. Важно, что эти отрезки должны быть упорядочены по возрастанию (или убыванию) координаты их пересечения с прямой. Заметим, что в процессе работы алгоритма отрезки могут добавляться в произвольные места этого упорядоченной множества, удаляться из произвольных мест или меняться местами друг с другом.&lt;br /&gt;
&lt;br /&gt;
===Важная мысль===&lt;br /&gt;
Попробуем найти событие, которое случится раньше всех других, если наша прямая уже пересекает какие-то отрезки. Нам, в данный момент, интересен случай, когда это событие является пересечением отрезков. Важно, что в этом пересечении участвуют два отрезка, которые обязательно являются соседними в нашем статусе.&lt;br /&gt;
&lt;br /&gt;
====Доказательство====&lt;br /&gt;
Предположим, что это не так. Значит, между этими двумя пересекающимися отрезками существует еще хотя бы один. Поскольку эти два отрезка пересекаются, то или третий пересекает перед их пересечением один из них, или пересекается с ними в той же точке. В любом случае, Важная мысль верна&lt;br /&gt;
&lt;br /&gt;
===В итоге===&lt;br /&gt;
[[Файл:anim1.gif|right|560|thumb|Пример работы алгоритма]]&lt;br /&gt;
Изначально у нас есть только события вида &amp;quot;начался отрезок&amp;quot; и &amp;quot;закончился отрезок&amp;quot;. События вида &amp;quot;пересекаются два отрезка&amp;quot; будут добавляться нами в множество еще не обработанных событий. Соответственно, алгоритм выглядит так: выбираем то событие из множества необработанных, у которого наименьшая координата &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;, обрабатываем, делаем так, пока множество необработанных событий непустое. Плюс, на протяжении всего алгоритма должен поддерживаться следующий инвариант: в множество необработанных событий уже добавлены все пересечения отрезков, которые в текущем статусе текущие.&lt;br /&gt;
&lt;br /&gt;
===Обработка событий===&lt;br /&gt;
====Событие &amp;quot;начало отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка,  между которыми будет находится тот, который начинается. После этого добавляем его в статус на это место и точки его пересечения с соседними добавляем в множество необработанных событий.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;конец отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе отрезок, который заканчивается. Удаляем его оттуда, после чего в множество необработанных событий добавляем точку, в которой пересекаются отрезки, которые были соседями заканчивающегося в старом статусе. Это необходимо, потому что в новом статусе они станут соседними. Заметим, что добавляемое событие может уже находиться в множестве, но нас это совершенно не напрягает.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;пересечение отрезков&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка, которые пересекаются. Меняем их местами (это действительно происходит). После этого добавляем в множество пересечения двух новых пар соседей, которые появились после перестановки пересекшихся отрезков.&lt;br /&gt;
&lt;br /&gt;
==Обработка &amp;quot;нехороших случаев&amp;quot;==&lt;br /&gt;
===Сканирующая точка===&lt;br /&gt;
Решим, для начала, вопрос с вертикальными отрезками. Важно, что заодно пропадет и проблема с обработкой событий, имеющих одинаковую координату по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:anim2.gif|right|560|thumb|Сканирующая точка]]&lt;br /&gt;
Слегка поменяем нашу концепцию. Сканирующая прямая теперь становится не совсем прямой. Теперь у нас появляется, скорее, сканирующая точка. Суть изменения в следующем: в случае, если несколько событий попадают на одну вертикальную прямую, мы их обрабатываем в порядке возрастания координаты по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Внимательный читатель сейчас, наверное, воскликнет: &amp;quot;А как же тогда наш статус? Ведь отрезки не могут пересекать точку!&amp;quot;. Однако и это не является проблемой. Если отрезок, который лежит в статусе, не вертикален, то он сортируется по своей координате &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, в которой он пересекается с вертикальной прямой, проведенной через нашу точку (да, это бывшая сканирующая прямая). А вот если отрезок вертикален, то его параметром является как раз ордината &amp;quot;сканирующей точки&amp;quot;. &amp;lt;s&amp;gt;Если внимательно подумать, то все будет корректно.&amp;lt;/s&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Несколько отрезков в одной точке===&lt;br /&gt;
====Первый метод решения проблемы====&lt;br /&gt;
У нас есть упорядоченное множество необработанных событий. Давайте перед добавлением события будем проверять, а нет ли его там. Если оно там уже есть, то события вида &amp;quot;в этой точке перечекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&amp;quot;, превратится в событие вида &amp;quot;в этой точке пересекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;&amp;quot;. В процессе обработки этой точки порядок следования в статусе всех отрезков, пересекающихся в ней, просто инвертируется. Соответственно, проблема решилась.&lt;br /&gt;
&lt;br /&gt;
====Второй метод решения проблемы====&lt;br /&gt;
На самом деле, посмотрим более внимательно, что произойдет в этой точке. Все пересечения всех пар обработаются. Всего таких пар &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt;, где в точке пересекается &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отрезков. Если в некой перестановке делается &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt; элементарных транспозиций, и ни одна из них не повторяется, то перестановка становится инвертированной. Так что, даже если оставить все как есть, то все будет работать. &amp;lt;s&amp;gt;Такие дела.&amp;lt;/s&amp;gt; Здесь тоже должна быть соответствующая анимашка.&lt;br /&gt;
&lt;br /&gt;
===СНМ вместо отрезков===&lt;br /&gt;
'''Внимание! Этот раздел должен интересовать только &amp;lt;s&amp;gt;задротов&amp;lt;/s&amp;gt; любознательных, так как он описывает разбор случая, который нам, по обещанию Ковалева, не встретится.'''&lt;br /&gt;
Нам остался последний сложный случай: наложение двух или более отрезков друг для друга. Давайте теперь вместо просто отрезков будем класть в СНМ следующее: множество отрезков, которые на данном этапе накладываются друг на друга. Понятно, что при добавлении нового отрезка он или создает свое множество, или добавляется в уже существующее. При удалении удаляется из множества, если оно осталось пустым - удаляется и само множество. А при пересечении с другим множеством попарно пересекаются все отрезки из двух множеств. При этом важно, что все отрезки, накладывающиеся друг на друга, должны занимать в статусе одну ячейку, т. е. являться одним множеством.&lt;br /&gt;
&lt;br /&gt;
==Реализация алгоритма==&lt;br /&gt;
===Двоичное дерево поиска в качестве статуса===&lt;br /&gt;
Из определения статуса ясно, какую структуру удобно использовать в качестве статуса: двоичное дерево поиска. В нем удобно делать все необходимые операции, и выполняться они будут за &amp;lt;tex&amp;gt;O(log_2(n))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Реализация множества необработанных событий===&lt;br /&gt;
====Приоритетная очередь====&lt;br /&gt;
Опять же, эта идея возникает в процессе описания этого множества. При этом понятно, что точки сравниваются сначала по абсциссе, в случае равенства - по ординате.&lt;br /&gt;
====Двоичное дерево поиска====&lt;br /&gt;
В принципе, вполне себе вариант реализации упорядоченного множества. Но его стоит использовать только тогда, когда мы хотим рассматривать пересечение нескольких отрезков в одной точке в качестве отдельного случая, а не как несколько попарных пересечений. Заметим, что это существенно усложняет реализацию.&lt;br /&gt;
&lt;br /&gt;
===Наконец, абсолютная точность===&lt;br /&gt;
Заметим, что мы не умеем получать абсолютно точные координаты пересечения двух отрезков. Однако, мы умеем представлять эти координаты в качестве суммы произведений нескольких чисел (просто пересечение прямых и раскрытие скобок в верхней части дроби). А сами координаты нам и не требуются, нам необходимо только уметь сравнивать эти координаты друг с другом. Сравнивать же эти суммы произведений с другими такими же суммами и с обычными числами (в обобщенном представлении тоже такими же суммами) мы тоже умеем. Победа!&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=14169</id>
		<title>Алгоритм Бентли-Оттмана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=14169"/>
				<updated>2011-12-09T03:59:33Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Бентли-Оттмана(англ. Bentley-Ottmann) - алгоритм, позволяющий по множеству отрезков на плоскости получить множество точек, в которых эти отрезки пересекаются, при этом для каждой точки алгоритм выдает множество отрезков, пересекающихся в ней.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
[[Файл:pic1.jpg|right|560|thumb|Пример результата работы алгоритма]]&lt;br /&gt;
На плоскости лежит &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; отрезков, каждый из них задан координатами своих концов. Требуется по этим данным определить множество точек, в которых эти отрезки пересекаются. Однако, не всегда координаты точки можно абсолютно точно представить с помощью вещественных типов данных. Поэтому характеризовать каждую точку будем множеством отрезков, которые пересекаются в этой точке.&lt;br /&gt;
&lt;br /&gt;
Для упрощения понимания введем два ограничения на входные данные:&lt;br /&gt;
* не существует вертикальных отрезков&lt;br /&gt;
* не существует пары отрезков, имеющих более одной общей точки&lt;br /&gt;
* никакие три отрезка не пересекаются в одной точке&lt;br /&gt;
&lt;br /&gt;
Как обрабатывать эти случаи будет объяснено позднее.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
===Основная идея===&lt;br /&gt;
Алгоритм будет основан на идее сканирующей прямой. Опишем три типа событий, которые мы и будем обрабатывать:&lt;br /&gt;
* начался новый отрезок&lt;br /&gt;
* два отрезка пересеклись&lt;br /&gt;
* отрезок закончился&lt;br /&gt;
&lt;br /&gt;
Сканирующая прямая будет расположена параллельно оси ординат, и двигаться вдоль оси абсцисс в сторону ее положительного направления. Учитывая введенные ограничения на входные данные, прямая никогда не будет проходить через два события одновременно.&lt;br /&gt;
&lt;br /&gt;
===Статус===&lt;br /&gt;
[[Файл:pic2.jpg|right|560|thumb|Иллюстрация определения статуса]]&lt;br /&gt;
Назовем статусом множество, в которой содержатся все отрезки, пересекающие нашу сканирующую прямую. Важно, что эти отрезки должны быть упорядочены по возрастанию (или убыванию) координаты их пересечения с прямой. Заметим, что в процессе работы алгоритма отрезки могут добавляться в произвольные места этого упорядоченной множества, удаляться из произвольных мест или меняться местами друг с другом.&lt;br /&gt;
&lt;br /&gt;
===Важная мысль===&lt;br /&gt;
Попробуем найти событие, которое случится раньше всех других, если наша прямая уже пересекает какие-то отрезки. Нам, в данный момент, интересен случай, когда это событие является пересечением отрезков. Важно, что в этом пересечении участвуют два отрезка, которые обязательно являются соседними в нашем статусе.&lt;br /&gt;
&lt;br /&gt;
====Доказательство====&lt;br /&gt;
Предположим, что это не так. Значит, между этими двумя пересекающимися отрезками существует еще хотя бы один. Поскольку эти два отрезка пересекаются, то или третий пересекает перед их пересечением один из них, или пересекается с ними в той же точке. В любом случае, Важная мысль верна&lt;br /&gt;
&lt;br /&gt;
===В итоге===&lt;br /&gt;
[[Файл:anim1.gif|right|560|thumb|Пример работы алгоритма]]&lt;br /&gt;
Изначально у нас есть только события вида &amp;quot;начался отрезок&amp;quot; и &amp;quot;закончился отрезок&amp;quot;. События вида &amp;quot;пересекаются два отрезка&amp;quot; будут добавляться нами в множество еще не обработанных событий. Соответственно, алгоритм выглядит так: выбираем то событие из множества необработанных, у которого наименьшая координата &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;, обрабатываем, делаем так, пока множество необработанных событий непустое. Плюс, на протяжении всего алгоритма должен поддерживаться следующий инвариант: в множество необработанных событий уже добавлены все пересечения отрезков, которые в текущем статусе текущие.&lt;br /&gt;
&lt;br /&gt;
===Обработка событий===&lt;br /&gt;
====Событие &amp;quot;начало отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка,  между которыми будет находится тот, который начинается. После этого добавляем его в статус на это место и точки его пересечения с соседними добавляем в множество необработанных событий.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;конец отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе отрезок, который заканчивается. Удаляем его оттуда, после чего в множество необработанных событий добавляем точку, в которой пересекаются отрезки, которые были соседями заканчивающегося в старом статусе. Это необходимо, потому что в новом статусе они станут соседними. Заметим, что добавляемое событие может уже находиться в множестве, но нас это совершенно не напрягает.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;пересечение отрезков&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка, которые пересекаются. Меняем их местами (это действительно происходит). После этого добавляем в множество пересечения двух новых пар соседей, которые появились после перестановки пересекшихся отрезков.&lt;br /&gt;
&lt;br /&gt;
==Обработка &amp;quot;нехороших случаев&amp;quot;==&lt;br /&gt;
===Сканирующая точка===&lt;br /&gt;
Решим, для начала, вопрос с вертикальными отрезками. Важно, что заодно пропадет и проблема с обработкой событий, имеющих одинаковую координату по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:anim2.gif|right|560|thumb|Сканирующая точка]]&lt;br /&gt;
Слегка поменяем нашу концепцию. Сканирующая прямая теперь становится не совсем прямой. Теперь у нас появляется, скорее, сканирующая точка. Суть изменения в следующем: в случае, если несколько событий попадают на одну вертикальную прямую, мы их обрабатываем в порядке возрастания координаты по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Внимательный читатель сейчас, наверное, воскликнет: &amp;quot;А как же тогда наш статус? Ведь отрезки не могут пересекать точку!&amp;quot;. Однако и это не является проблемой. Если отрезок, который лежит в статусе, не вертикален, то он сортируется по своей координате &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, в которой он пересекается с вертикальной прямой, проведенной через нашу точку (да, это бывшая сканирующая прямая). А вот если отрезок вертикален, то его параметром является как раз ордината &amp;quot;сканирующей точки&amp;quot;. &amp;lt;s&amp;gt;Если внимательно подумать, то все будет корректно.&amp;lt;/s&amp;gt;Здесь должна быть анимашка, в которой показывается, что все будет корректно.&lt;br /&gt;
&lt;br /&gt;
===Несколько отрезков в одной точке===&lt;br /&gt;
====Первый метод решения проблемы====&lt;br /&gt;
У нас есть упорядоченное множество необработанных событий. Давайте перед добавлением события будем проверять, а нет ли его там. Если оно там уже есть, то события вида &amp;quot;в этой точке перечекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&amp;quot;, превратится в событие вида &amp;quot;в этой точке пересекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;&amp;quot;. В процессе обработки этой точки порядок следования в статусе всех отрезков, пересекающихся в ней, просто инвертируется. Соответственно, проблема решилась.&lt;br /&gt;
&lt;br /&gt;
====Второй метод решения проблемы====&lt;br /&gt;
На самом деле, посмотрим более внимательно, что произойдет в этой точке. Все пересечения всех пар обработаются. Всего таких пар &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt;, где в точке пересекается &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отрезков. Если в некой перестановке делается &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt; элементарных транспозиций, и ни одна из них не повторяется, то перестановка становится инвертированной. Так что, даже если оставить все как есть, то все будет работать. &amp;lt;s&amp;gt;Такие дела.&amp;lt;/s&amp;gt; Здесь тоже должна быть соответствующая анимашка.&lt;br /&gt;
&lt;br /&gt;
===СНМ вместо отрезков===&lt;br /&gt;
'''Внимание! Этот раздел должен интересовать только &amp;lt;s&amp;gt;задротов&amp;lt;/s&amp;gt; любознательных, так как он описывает разбор случая, который нам, по обещанию Ковалева, не встретится.'''&lt;br /&gt;
Нам остался последний сложный случай: наложение двух или более отрезков друг для друга. Давайте теперь вместо просто отрезков будем класть в СНМ следующее: множество отрезков, которые на данном этапе накладываются друг на друга. Понятно, что при добавлении нового отрезка он или создает свое множество, или добавляется в уже существующее. При удалении удаляется из множества, если оно осталось пустым - удаляется и само множество. А при пересечении с другим множеством попарно пересекаются все отрезки из двух множеств. При этом важно, что все отрезки, накладывающиеся друг на друга, должны занимать в статусе одну ячейку, т. е. являться одним множеством.&lt;br /&gt;
&lt;br /&gt;
==Реализация алгоритма==&lt;br /&gt;
===Двоичное дерево поиска в качестве статуса===&lt;br /&gt;
Из определения статуса ясно, какую структуру удобно использовать в качестве статуса: двоичное дерево поиска. В нем удобно делать все необходимые операции, и выполняться они будут за &amp;lt;tex&amp;gt;O(log_2(n))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Реализация множества необработанных событий===&lt;br /&gt;
====Приоритетная очередь====&lt;br /&gt;
Опять же, эта идея возникает в процессе описания этого множества. При этом понятно, что точки сравниваются сначала по абсциссе, в случае равенства - по ординате.&lt;br /&gt;
====Двоичное дерево поиска====&lt;br /&gt;
В принципе, вполне себе вариант реализации упорядоченного множества. Но его стоит использовать только тогда, когда мы хотим рассматривать пересечение нескольких отрезков в одной точке в качестве отдельного случая, а не как несколько попарных пересечений. Заметим, что это существенно усложняет реализацию.&lt;br /&gt;
&lt;br /&gt;
===Наконец, абсолютная точность===&lt;br /&gt;
Заметим, что мы не умеем получать абсолютно точные координаты пересечения двух отрезков. Однако, мы умеем представлять эти координаты в качестве суммы произведений нескольких чисел (просто пересечение прямых и раскрытие скобок в верхней части дроби). А сами координаты нам и не требуются, нам необходимо только уметь сравнивать эти координаты друг с другом. Сравнивать же эти суммы произведений с другими такими же суммами и с обычными числами (в обобщенном представлении тоже такими же суммами) мы тоже умеем. Победа!&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Anim2.gif&amp;diff=14168</id>
		<title>Файл:Anim2.gif</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Anim2.gif&amp;diff=14168"/>
				<updated>2011-12-09T03:58:20Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=14167</id>
		<title>Алгоритм Бентли-Оттмана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=14167"/>
				<updated>2011-12-09T03:57:51Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Бентли-Оттмана(англ. Bentley-Ottmann) - алгоритм, позволяющий по множеству отрезков на плоскости получить множество точек, в которых эти отрезки пересекаются, при этом для каждой точки алгоритм выдает множество отрезков, пересекающихся в ней.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
[[Файл:pic1.jpg|right|391|thumb|Пример результата работы алгоритма]]&lt;br /&gt;
На плоскости лежит &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; отрезков, каждый из них задан координатами своих концов. Требуется по этим данным определить множество точек, в которых эти отрезки пересекаются. Однако, не всегда координаты точки можно абсолютно точно представить с помощью вещественных типов данных. Поэтому характеризовать каждую точку будем множеством отрезков, которые пересекаются в этой точке.&lt;br /&gt;
&lt;br /&gt;
Для упрощения понимания введем два ограничения на входные данные:&lt;br /&gt;
* не существует вертикальных отрезков&lt;br /&gt;
* не существует пары отрезков, имеющих более одной общей точки&lt;br /&gt;
* никакие три отрезка не пересекаются в одной точке&lt;br /&gt;
&lt;br /&gt;
Как обрабатывать эти случаи будет объяснено позднее.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
===Основная идея===&lt;br /&gt;
Алгоритм будет основан на идее сканирующей прямой. Опишем три типа событий, которые мы и будем обрабатывать:&lt;br /&gt;
* начался новый отрезок&lt;br /&gt;
* два отрезка пересеклись&lt;br /&gt;
* отрезок закончился&lt;br /&gt;
&lt;br /&gt;
Сканирующая прямая будет расположена параллельно оси ординат, и двигаться вдоль оси абсцисс в сторону ее положительного направления. Учитывая введенные ограничения на входные данные, прямая никогда не будет проходить через два события одновременно.&lt;br /&gt;
&lt;br /&gt;
===Статус===&lt;br /&gt;
[[Файл:pic2.jpg|right|391|thumb|Иллюстрация определения статуса]]&lt;br /&gt;
Назовем статусом множество, в которой содержатся все отрезки, пересекающие нашу сканирующую прямую. Важно, что эти отрезки должны быть упорядочены по возрастанию (или убыванию) координаты их пересечения с прямой. Заметим, что в процессе работы алгоритма отрезки могут добавляться в произвольные места этого упорядоченной множества, удаляться из произвольных мест или меняться местами друг с другом.&lt;br /&gt;
&lt;br /&gt;
===Важная мысль===&lt;br /&gt;
Попробуем найти событие, которое случится раньше всех других, если наша прямая уже пересекает какие-то отрезки. Нам, в данный момент, интересен случай, когда это событие является пересечением отрезков. Важно, что в этом пересечении участвуют два отрезка, которые обязательно являются соседними в нашем статусе.&lt;br /&gt;
&lt;br /&gt;
====Доказательство====&lt;br /&gt;
Предположим, что это не так. Значит, между этими двумя пересекающимися отрезками существует еще хотя бы один. Поскольку эти два отрезка пересекаются, то или третий пересекает перед их пересечением один из них, или пересекается с ними в той же точке. В любом случае, Важная мысль верна&lt;br /&gt;
&lt;br /&gt;
===В итоге===&lt;br /&gt;
[[Файл:anim1.gif|right|391|thumb|Пример работы алгоритма]]&lt;br /&gt;
Изначально у нас есть только события вида &amp;quot;начался отрезок&amp;quot; и &amp;quot;закончился отрезок&amp;quot;. События вида &amp;quot;пересекаются два отрезка&amp;quot; будут добавляться нами в множество еще не обработанных событий. Соответственно, алгоритм выглядит так: выбираем то событие из множества необработанных, у которого наименьшая координата &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;, обрабатываем, делаем так, пока множество необработанных событий непустое. Плюс, на протяжении всего алгоритма должен поддерживаться следующий инвариант: в множество необработанных событий уже добавлены все пересечения отрезков, которые в текущем статусе текущие.&lt;br /&gt;
&lt;br /&gt;
===Обработка событий===&lt;br /&gt;
====Событие &amp;quot;начало отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка,  между которыми будет находится тот, который начинается. После этого добавляем его в статус на это место и точки его пересечения с соседними добавляем в множество необработанных событий.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;конец отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе отрезок, который заканчивается. Удаляем его оттуда, после чего в множество необработанных событий добавляем точку, в которой пересекаются отрезки, которые были соседями заканчивающегося в старом статусе. Это необходимо, потому что в новом статусе они станут соседними. Заметим, что добавляемое событие может уже находиться в множестве, но нас это совершенно не напрягает.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;пересечение отрезков&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка, которые пересекаются. Меняем их местами (это действительно происходит). После этого добавляем в множество пересечения двух новых пар соседей, которые появились после перестановки пересекшихся отрезков.&lt;br /&gt;
&lt;br /&gt;
==Обработка &amp;quot;нехороших случаев&amp;quot;==&lt;br /&gt;
===Сканирующая точка===&lt;br /&gt;
Решим, для начала, вопрос с вертикальными отрезками. Важно, что заодно пропадет и проблема с обработкой событий, имеющих одинаковую координату по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Файл:anim2.gif|right|391|thumb|Сканирующая точка]]&lt;br /&gt;
Слегка поменяем нашу концепцию. Сканирующая прямая теперь становится не совсем прямой. Теперь у нас появляется, скорее, сканирующая точка. Суть изменения в следующем: в случае, если несколько событий попадают на одну вертикальную прямую, мы их обрабатываем в порядке возрастания координаты по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Внимательный читатель сейчас, наверное, воскликнет: &amp;quot;А как же тогда наш статус? Ведь отрезки не могут пересекать точку!&amp;quot;. Однако и это не является проблемой. Если отрезок, который лежит в статусе, не вертикален, то он сортируется по своей координате &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, в которой он пересекается с вертикальной прямой, проведенной через нашу точку (да, это бывшая сканирующая прямая). А вот если отрезок вертикален, то его параметром является как раз ордината &amp;quot;сканирующей точки&amp;quot;. &amp;lt;s&amp;gt;Если внимательно подумать, то все будет корректно.&amp;lt;/s&amp;gt;Здесь должна быть анимашка, в которой показывается, что все будет корректно.&lt;br /&gt;
&lt;br /&gt;
===Несколько отрезков в одной точке===&lt;br /&gt;
====Первый метод решения проблемы====&lt;br /&gt;
У нас есть упорядоченное множество необработанных событий. Давайте перед добавлением события будем проверять, а нет ли его там. Если оно там уже есть, то события вида &amp;quot;в этой точке перечекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&amp;quot;, превратится в событие вида &amp;quot;в этой точке пересекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;&amp;quot;. В процессе обработки этой точки порядок следования в статусе всех отрезков, пересекающихся в ней, просто инвертируется. Соответственно, проблема решилась.&lt;br /&gt;
&lt;br /&gt;
====Второй метод решения проблемы====&lt;br /&gt;
На самом деле, посмотрим более внимательно, что произойдет в этой точке. Все пересечения всех пар обработаются. Всего таких пар &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt;, где в точке пересекается &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отрезков. Если в некой перестановке делается &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt; элементарных транспозиций, и ни одна из них не повторяется, то перестановка становится инвертированной. Так что, даже если оставить все как есть, то все будет работать. &amp;lt;s&amp;gt;Такие дела.&amp;lt;/s&amp;gt; Здесь тоже должна быть соответствующая анимашка.&lt;br /&gt;
&lt;br /&gt;
===СНМ вместо отрезков===&lt;br /&gt;
'''Внимание! Этот раздел должен интересовать только &amp;lt;s&amp;gt;задротов&amp;lt;/s&amp;gt; любознательных, так как он описывает разбор случая, который нам, по обещанию Ковалева, не встретится.'''&lt;br /&gt;
Нам остался последний сложный случай: наложение двух или более отрезков друг для друга. Давайте теперь вместо просто отрезков будем класть в СНМ следующее: множество отрезков, которые на данном этапе накладываются друг на друга. Понятно, что при добавлении нового отрезка он или создает свое множество, или добавляется в уже существующее. При удалении удаляется из множества, если оно осталось пустым - удаляется и само множество. А при пересечении с другим множеством попарно пересекаются все отрезки из двух множеств. При этом важно, что все отрезки, накладывающиеся друг на друга, должны занимать в статусе одну ячейку, т. е. являться одним множеством.&lt;br /&gt;
&lt;br /&gt;
==Реализация алгоритма==&lt;br /&gt;
===Двоичное дерево поиска в качестве статуса===&lt;br /&gt;
Из определения статуса ясно, какую структуру удобно использовать в качестве статуса: двоичное дерево поиска. В нем удобно делать все необходимые операции, и выполняться они будут за &amp;lt;tex&amp;gt;O(log_2(n))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Реализация множества необработанных событий===&lt;br /&gt;
====Приоритетная очередь====&lt;br /&gt;
Опять же, эта идея возникает в процессе описания этого множества. При этом понятно, что точки сравниваются сначала по абсциссе, в случае равенства - по ординате.&lt;br /&gt;
====Двоичное дерево поиска====&lt;br /&gt;
В принципе, вполне себе вариант реализации упорядоченного множества. Но его стоит использовать только тогда, когда мы хотим рассматривать пересечение нескольких отрезков в одной точке в качестве отдельного случая, а не как несколько попарных пересечений. Заметим, что это существенно усложняет реализацию.&lt;br /&gt;
&lt;br /&gt;
===Наконец, абсолютная точность===&lt;br /&gt;
Заметим, что мы не умеем получать абсолютно точные координаты пересечения двух отрезков. Однако, мы умеем представлять эти координаты в качестве суммы произведений нескольких чисел (просто пересечение прямых и раскрытие скобок в верхней части дроби). А сами координаты нам и не требуются, нам необходимо только уметь сравнивать эти координаты друг с другом. Сравнивать же эти суммы произведений с другими такими же суммами и с обычными числами (в обобщенном представлении тоже такими же суммами) мы тоже умеем. Победа!&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Anim1.gif&amp;diff=14166</id>
		<title>Файл:Anim1.gif</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Anim1.gif&amp;diff=14166"/>
				<updated>2011-12-09T03:48:22Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Tmp.gif&amp;diff=13891</id>
		<title>Файл:Tmp.gif</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Tmp.gif&amp;diff=13891"/>
				<updated>2011-12-03T22:47:29Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13889</id>
		<title>Алгоритм Бентли-Оттмана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13889"/>
				<updated>2011-12-03T20:55:09Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: /* Сканирующая точка */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Бентли-Оттмана(англ. Bentley-Ottmann) - алгоритм, позволяющий по множеству отрезков на плоскости получить множество точек, в которых эти отрезки пересекаются, при этом для каждой точки алгоритм выдает множество отрезков, пересекающихся в ней.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
[[Файл:pic1.jpg|right|391|thumb|Пример результата работы алгоритма]]&lt;br /&gt;
На плоскости лежит &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; отрезков, каждый из них задан координатами своих концов. Требуется по этим данным определить множество точек, в которых эти отрезки пересекаются. Однако, не всегда координаты точки можно абсолютно точно представить с помощью вещественных типов данных. Поэтому характеризовать каждую точку будем множеством отрезков, которые пересекаются в этой точке.&lt;br /&gt;
&lt;br /&gt;
Для упрощения понимания введем два ограничения на входные данные:&lt;br /&gt;
* не существует вертикальных отрезков&lt;br /&gt;
* не существует пары отрезков, имеющих более одной общей точки&lt;br /&gt;
* никакие три отрезка не пересекаются в одной точке&lt;br /&gt;
&lt;br /&gt;
Как обрабатывать эти случаи будет объяснено позднее.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
===Основная идея===&lt;br /&gt;
Алгоритм будет основан на идее сканирующей прямой. Опишем три типа событий, которые мы и будем обрабатывать:&lt;br /&gt;
* начался новый отрезок&lt;br /&gt;
* два отрезка пересеклись&lt;br /&gt;
* отрезок закончился&lt;br /&gt;
&lt;br /&gt;
Сканирующая прямая будет расположена параллельно оси ординат, и двигаться вдоль оси абсцисс в сторону ее положительного направления. Учитывая введенные ограничения на входные данные, прямая никогда не будет проходить через два события одновременно.&lt;br /&gt;
&lt;br /&gt;
===Статус===&lt;br /&gt;
[[Файл:pic2.jpg|right|391|thumb|Иллюстрация определения статуса]]&lt;br /&gt;
Назовем статусом множество, в которой содержатся все отрезки, пересекающие нашу сканирующую прямую. Важно, что эти отрезки должны быть упорядочены по возрастанию (или убыванию) координаты их пересечения с прямой. Заметим, что в процессе работы алгоритма отрезки могут добавляться в произвольные места этого упорядоченной множества, удаляться из произвольных мест или меняться местами друг с другом.&lt;br /&gt;
&lt;br /&gt;
===Важная мысль===&lt;br /&gt;
Попробуем найти событие, которое случится раньше всех других, если наша прямая уже пересекает какие-то отрезки. Нам, в данный момент, интересен случай, когда это событие является пересечением отрезков. Важно, что в этом пересечении участвуют два отрезка, которые обязательно являются соседними в нашем статусе.&lt;br /&gt;
&lt;br /&gt;
====Доказательство====&lt;br /&gt;
Предположим, что это не так. Значит, между этими двумя пересекающимися отрезками существует еще хотя бы один. Поскольку эти два отрезка пересекаются, то или третий пересекает перед их пересечением один из них, или пересекается с ними в той же точке. В любом случае, Важная мысль верна&lt;br /&gt;
&lt;br /&gt;
===В итоге===&lt;br /&gt;
Изначально у нас есть только события вида &amp;quot;начался отрезок&amp;quot; и &amp;quot;закончился отрезок&amp;quot;. События вида &amp;quot;пересекаются два отрезка&amp;quot; будут добавляться нами в множество еще не обработанных событий. Соответственно, алгоритм выглядит так: выбираем то событие из множества необработанных, у которого наименьшая координата &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;, обрабатываем, делаем так, пока множество необработанных событий непустое. Плюс, на протяжении всего алгоритма должен поддерживаться следующий инвариант: в множество необработанных событий уже добавлены все пересечения отрезков, которые в текущем статусе текущие.&lt;br /&gt;
&lt;br /&gt;
===Обработка событий===&lt;br /&gt;
====Событие &amp;quot;начало отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка,  между которыми будет находится тот, который начинается. После этого добавляем его в статус на это место и точки его пересечения с соседними добавляем в множество необработанных событий.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;конец отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе отрезок, который заканчивается. Удаляем его оттуда, после чего в множество необработанных событий добавляем точку, в которой пересекаются отрезки, которые были соседями заканчивающегося в старом статусе. Это необходимо, потому что в новом статусе они станут соседними. Заметим, что добавляемое событие может уже находиться в множестве, но нас это совершенно не напрягает.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;пересечение отрезков&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка, которые пересекаются. Меняем их местами (это действительно происходит). После этого добавляем в множество пересечения двух новых пар соседей, которые появились после перестановки пересекшихся отрезков.&lt;br /&gt;
&lt;br /&gt;
==Обработка &amp;quot;нехороших случаев&amp;quot;==&lt;br /&gt;
===Сканирующая точка===&lt;br /&gt;
Решим, для начала, вопрос с вертикальными отрезками. Важно, что заодно пропадет и проблема с обработкой событий, имеющих одинаковую координату по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Слегка поменяем нашу концепцию. Сканирующая прямая теперь становится не совсем прямой. Теперь у нас появляется, скорее, сканирующая точка. Суть изменения в следующем: в случае, если несколько событий попадают на одну вертикальную прямую, мы их обрабатываем в порядке возрастания координаты по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Внимательный читатель сейчас, наверное, воскликнет: &amp;quot;А как же тогда наш статус? Ведь отрезки не могут пересекать точку!&amp;quot;. Однако и это не является проблемой. Если отрезок, который лежит в статусе, не вертикален, то он сортируется по своей координате &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, в которой он пересекается с вертикальной прямой, проведенной через нашу точку (да, это бывшая сканирующая прямая). А вот если отрезок вертикален, то его параметром является как раз ордината &amp;quot;сканирующей точки&amp;quot;. &amp;lt;s&amp;gt;Если внимательно подумать, то все будет корректно.&amp;lt;/s&amp;gt;Здесь должна быть анимашка, в которой показывается, что все будет корректно.&lt;br /&gt;
&lt;br /&gt;
===Несколько отрезков в одной точке===&lt;br /&gt;
====Первый метод решения проблемы====&lt;br /&gt;
У нас есть упорядоченное множество необработанных событий. Давайте перед добавлением события будем проверять, а нет ли его там. Если оно там уже есть, то события вида &amp;quot;в этой точке перечекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&amp;quot;, превратится в событие вида &amp;quot;в этой точке пересекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;&amp;quot;. В процессе обработки этой точки порядок следования в статусе всех отрезков, пересекающихся в ней, просто инвертируется. Соответственно, проблема решилась.&lt;br /&gt;
&lt;br /&gt;
====Второй метод решения проблемы====&lt;br /&gt;
На самом деле, посмотрим более внимательно, что произойдет в этой точке. Все пересечения всех пар обработаются. Всего таких пар &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt;, где в точке пересекается &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отрезков. Если в некой перестановке делается &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt; элементарных транспозиций, и ни одна из них не повторяется, то перестановка становится инвертированной. Так что, даже если оставить все как есть, то все будет работать. &amp;lt;s&amp;gt;Такие дела.&amp;lt;/s&amp;gt; Здесь тоже должна быть соответствующая анимашка.&lt;br /&gt;
&lt;br /&gt;
===СНМ вместо отрезков===&lt;br /&gt;
'''Внимание! Этот раздел должен интересовать только &amp;lt;s&amp;gt;задротов&amp;lt;/s&amp;gt; любознательных, так как он описывает разбор случая, который нам, по обещанию Ковалева, не встретится.'''&lt;br /&gt;
Нам остался последний сложный случай: наложение двух или более отрезков друг для друга. Давайте теперь вместо просто отрезков будем класть в СНМ следующее: множество отрезков, которые на данном этапе накладываются друг на друга. Понятно, что при добавлении нового отрезка он или создает свое множество, или добавляется в уже существующее. При удалении удаляется из множества, если оно осталось пустым - удаляется и само множество. А при пересечении с другим множеством попарно пересекаются все отрезки из двух множеств. При этом важно, что все отрезки, накладывающиеся друг на друга, должны занимать в статусе одну ячейку, т. е. являться одним множеством.&lt;br /&gt;
&lt;br /&gt;
==Реализация алгоритма==&lt;br /&gt;
===Двоичное дерево поиска в качестве статуса===&lt;br /&gt;
Из определения статуса ясно, какую структуру удобно использовать в качестве статуса: двоичное дерево поиска. В нем удобно делать все необходимые операции, и выполняться они будут за &amp;lt;tex&amp;gt;O(log_2(n))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Реализация множества необработанных событий===&lt;br /&gt;
====Приоритетная очередь====&lt;br /&gt;
Опять же, эта идея возникает в процессе описания этого множества. При этом понятно, что точки сравниваются сначала по абсциссе, в случае равенства - по ординате.&lt;br /&gt;
====Двоичное дерево поиска====&lt;br /&gt;
В принципе, вполне себе вариант реализации упорядоченного множества. Но его стоит использовать только тогда, когда мы хотим рассматривать пересечение нескольких отрезков в одной точке в качестве отдельного случая, а не как несколько попарных пересечений. Заметим, что это существенно усложняет реализацию.&lt;br /&gt;
&lt;br /&gt;
===Наконец, абсолютная точность===&lt;br /&gt;
Заметим, что мы не умеем получать абсолютно точные координаты пересечения двух отрезков. Однако, мы умеем представлять эти координаты в качестве суммы произведений нескольких чисел (просто пересечение прямых и раскрытие скобок в верхней части дроби). А сами координаты нам и не требуются, нам необходимо только уметь сравнивать эти координаты друг с другом. Сравнивать же эти суммы произведений с другими такими же суммами и с обычными числами (в обобщенном представлении тоже такими же суммами) мы тоже умеем. Победа!&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Pic2.jpg&amp;diff=13888</id>
		<title>Файл:Pic2.jpg</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Pic2.jpg&amp;diff=13888"/>
				<updated>2011-12-03T20:53:22Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: загружена новая версия «Файл:Pic2.jpg»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Pic2.jpg&amp;diff=13887</id>
		<title>Файл:Pic2.jpg</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Pic2.jpg&amp;diff=13887"/>
				<updated>2011-12-03T20:51:51Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13886</id>
		<title>Алгоритм Бентли-Оттмана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13886"/>
				<updated>2011-12-03T20:51:31Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Бентли-Оттмана(англ. Bentley-Ottmann) - алгоритм, позволяющий по множеству отрезков на плоскости получить множество точек, в которых эти отрезки пересекаются, при этом для каждой точки алгоритм выдает множество отрезков, пересекающихся в ней.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
[[Файл:pic1.jpg|right|391|thumb|Пример результата работы алгоритма]]&lt;br /&gt;
На плоскости лежит &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; отрезков, каждый из них задан координатами своих концов. Требуется по этим данным определить множество точек, в которых эти отрезки пересекаются. Однако, не всегда координаты точки можно абсолютно точно представить с помощью вещественных типов данных. Поэтому характеризовать каждую точку будем множеством отрезков, которые пересекаются в этой точке.&lt;br /&gt;
&lt;br /&gt;
Для упрощения понимания введем два ограничения на входные данные:&lt;br /&gt;
* не существует вертикальных отрезков&lt;br /&gt;
* не существует пары отрезков, имеющих более одной общей точки&lt;br /&gt;
* никакие три отрезка не пересекаются в одной точке&lt;br /&gt;
&lt;br /&gt;
Как обрабатывать эти случаи будет объяснено позднее.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
===Основная идея===&lt;br /&gt;
Алгоритм будет основан на идее сканирующей прямой. Опишем три типа событий, которые мы и будем обрабатывать:&lt;br /&gt;
* начался новый отрезок&lt;br /&gt;
* два отрезка пересеклись&lt;br /&gt;
* отрезок закончился&lt;br /&gt;
&lt;br /&gt;
Сканирующая прямая будет расположена параллельно оси ординат, и двигаться вдоль оси абсцисс в сторону ее положительного направления. Учитывая введенные ограничения на входные данные, прямая никогда не будет проходить через два события одновременно.&lt;br /&gt;
&lt;br /&gt;
===Статус===&lt;br /&gt;
[[Файл:pic2.jpg|right|391|thumb|Иллюстрация определения статуса]]&lt;br /&gt;
Назовем статусом множество, в которой содержатся все отрезки, пересекающие нашу сканирующую прямую. Важно, что эти отрезки должны быть упорядочены по возрастанию (или убыванию) координаты их пересечения с прямой. Заметим, что в процессе работы алгоритма отрезки могут добавляться в произвольные места этого упорядоченной множества, удаляться из произвольных мест или меняться местами друг с другом.&lt;br /&gt;
&lt;br /&gt;
===Важная мысль===&lt;br /&gt;
Попробуем найти событие, которое случится раньше всех других, если наша прямая уже пересекает какие-то отрезки. Нам, в данный момент, интересен случай, когда это событие является пересечением отрезков. Важно, что в этом пересечении участвуют два отрезка, которые обязательно являются соседними в нашем статусе.&lt;br /&gt;
&lt;br /&gt;
====Доказательство====&lt;br /&gt;
Предположим, что это не так. Значит, между этими двумя пересекающимися отрезками существует еще хотя бы один. Поскольку эти два отрезка пересекаются, то или третий пересекает перед их пересечением один из них, или пересекается с ними в той же точке. В любом случае, Важная мысль верна&lt;br /&gt;
&lt;br /&gt;
===В итоге===&lt;br /&gt;
Изначально у нас есть только события вида &amp;quot;начался отрезок&amp;quot; и &amp;quot;закончился отрезок&amp;quot;. События вида &amp;quot;пересекаются два отрезка&amp;quot; будут добавляться нами в множество еще не обработанных событий. Соответственно, алгоритм выглядит так: выбираем то событие из множества необработанных, у которого наименьшая координата &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;, обрабатываем, делаем так, пока множество необработанных событий непустое. Плюс, на протяжении всего алгоритма должен поддерживаться следующий инвариант: в множество необработанных событий уже добавлены все пересечения отрезков, которые в текущем статусе текущие.&lt;br /&gt;
&lt;br /&gt;
===Обработка событий===&lt;br /&gt;
====Событие &amp;quot;начало отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка,  между которыми будет находится тот, который начинается. После этого добавляем его в статус на это место и точки его пересечения с соседними добавляем в множество необработанных событий.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;конец отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе отрезок, который заканчивается. Удаляем его оттуда, после чего в множество необработанных событий добавляем точку, в которой пересекаются отрезки, которые были соседями заканчивающегося в старом статусе. Это необходимо, потому что в новом статусе они станут соседними. Заметим, что добавляемое событие может уже находиться в множестве, но нас это совершенно не напрягает.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;пересечение отрезков&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка, которые пересекаются. Меняем их местами (это действительно происходит). После этого добавляем в множество пересечения двух новых пар соседей, которые появились после перестановки пересекшихся отрезков.&lt;br /&gt;
&lt;br /&gt;
==Обработка &amp;quot;нехороших случаев&amp;quot;==&lt;br /&gt;
===Сканирующая точка===&lt;br /&gt;
Решим, для начала, вопрос с вертикальными отрезками. Важно, что заодно пропадет и проблема с обработкой событий, имеющих одинаковую координату по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Слегка поменяем нашу концепцию. Сканирующая прямая теперь становится не совсем прямой. Теперь у нас появляется, скорее, сканирующая точка. Суть изменения в следующем: в случае, если несколько событий попадают на одну вертикальную прямую, мы их обрабатываем в порядке возрастания координаты по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Внимательный читатель сейчас наверное воскликнет: &amp;quot;А как же тогда наш статус? Ведь отрезки не могут пересекать точку!&amp;quot;. Однако и это не является проблемой. Если отрезок, который лежит в статусе, не вертикален, то он сортируется по своей координате &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, в которой он пересекается с вертикальной прямой, проведенной через нашу точку (да, это бывшая сканирующая прямая). А вот если отрезок вертикален, то его параметром является как раз ордината &amp;quot;сканирующей точки&amp;quot;. &amp;lt;s&amp;gt;Если внимательно подумать, то все будет корректно.&amp;lt;/s&amp;gt;Здесь должна быть анимашка, в которой показывается, что все будет корректно.&lt;br /&gt;
&lt;br /&gt;
===Несколько отрезков в одной точке===&lt;br /&gt;
====Первый метод решения проблемы====&lt;br /&gt;
У нас есть упорядоченное множество необработанных событий. Давайте перед добавлением события будем проверять, а нет ли его там. Если оно там уже есть, то события вида &amp;quot;в этой точке перечекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&amp;quot;, превратится в событие вида &amp;quot;в этой точке пересекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;&amp;quot;. В процессе обработки этой точки порядок следования в статусе всех отрезков, пересекающихся в ней, просто инвертируется. Соответственно, проблема решилась.&lt;br /&gt;
&lt;br /&gt;
====Второй метод решения проблемы====&lt;br /&gt;
На самом деле, посмотрим более внимательно, что произойдет в этой точке. Все пересечения всех пар обработаются. Всего таких пар &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt;, где в точке пересекается &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отрезков. Если в некой перестановке делается &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt; элементарных транспозиций, и ни одна из них не повторяется, то перестановка становится инвертированной. Так что, даже если оставить все как есть, то все будет работать. &amp;lt;s&amp;gt;Такие дела.&amp;lt;/s&amp;gt; Здесь тоже должна быть соответствующая анимашка.&lt;br /&gt;
&lt;br /&gt;
===СНМ вместо отрезков===&lt;br /&gt;
'''Внимание! Этот раздел должен интересовать только &amp;lt;s&amp;gt;задротов&amp;lt;/s&amp;gt; любознательных, так как он описывает разбор случая, который нам, по обещанию Ковалева, не встретится.'''&lt;br /&gt;
Нам остался последний сложный случай: наложение двух или более отрезков друг для друга. Давайте теперь вместо просто отрезков будем класть в СНМ следующее: множество отрезков, которые на данном этапе накладываются друг на друга. Понятно, что при добавлении нового отрезка он или создает свое множество, или добавляется в уже существующее. При удалении удаляется из множества, если оно осталось пустым - удаляется и само множество. А при пересечении с другим множеством попарно пересекаются все отрезки из двух множеств. При этом важно, что все отрезки, накладывающиеся друг на друга, должны занимать в статусе одну ячейку, т. е. являться одним множеством.&lt;br /&gt;
&lt;br /&gt;
==Реализация алгоритма==&lt;br /&gt;
===Двоичное дерево поиска в качестве статуса===&lt;br /&gt;
Из определения статуса ясно, какую структуру удобно использовать в качестве статуса: двоичное дерево поиска. В нем удобно делать все необходимые операции, и выполняться они будут за &amp;lt;tex&amp;gt;O(log_2(n))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Реализация множества необработанных событий===&lt;br /&gt;
====Приоритетная очередь====&lt;br /&gt;
Опять же, эта идея возникает в процессе описания этого множества. При этом понятно, что точки сравниваются сначала по абсциссе, в случае равенства - по ординате.&lt;br /&gt;
====Двоичное дерево поиска====&lt;br /&gt;
В принципе, вполне себе вариант реализации упорядоченного множества. Но его стоит использовать только тогда, когда мы хотим рассматривать пересечение нескольких отрезков в одной точке в качестве отдельного случая, а не как несколько попарных пересечений. Заметим, что это существенно усложняет реализацию.&lt;br /&gt;
&lt;br /&gt;
===Наконец, абсолютная точность===&lt;br /&gt;
Заметим, что мы не умеем получать абсолютно точные координаты пересечения двух отрезков. Однако, мы умеем представлять эти координаты в качестве суммы произведений нескольких чисел (просто пересечение прямых и раскрытие скобок в верхней части дроби). А сами координаты нам и не требуются, нам необходимо только уметь сравнивать эти координаты друг с другом. Сравнивать же эти суммы произведений с другими такими же суммами и с обычными числами (в обобщенном представлении тоже такими же суммами) мы тоже умеем. Победа!&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13885</id>
		<title>Алгоритм Бентли-Оттмана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13885"/>
				<updated>2011-12-03T20:46:06Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Бентли-Оттмана(англ. Bentley-Ottmann) - алгоритм, позволяющий по множеству отрезков на плоскости получить множество точек, в которых эти отрезки пересекаются, при этом для каждой точки алгоритм выдает множество отрезков, пересекающихся в ней.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
[[Файл:pic1.jpg|right|391|thumb|Пример результата работы алгоритма]]&lt;br /&gt;
На плоскости лежит &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; отрезков, каждый из них задан координатами своих концов. Требуется по этим данным определить множество точек, в которых эти отрезки пересекаются. Однако, не всегда координаты точки можно абсолютно точно представить с помощью вещественных типов данных. Поэтому характеризовать каждую точку будем множеством отрезков, которые пересекаются в этой точке.&lt;br /&gt;
&lt;br /&gt;
Для упрощения понимания введем два ограничения на входные данные:&lt;br /&gt;
* не существует вертикальных отрезков&lt;br /&gt;
* не существует пары отрезков, имеющих более одной общей точки&lt;br /&gt;
* никакие три отрезка не пересекаются в одной точке&lt;br /&gt;
&lt;br /&gt;
Как обрабатывать эти случаи будет объяснено позднее.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
===Основная идея===&lt;br /&gt;
Алгоритм будет основан на идее сканирующей прямой. Опишем три типа событий, которые мы и будем обрабатывать:&lt;br /&gt;
* начался новый отрезок&lt;br /&gt;
* два отрезка пересеклись&lt;br /&gt;
* отрезок закончился&lt;br /&gt;
&lt;br /&gt;
Сканирующая прямая будет расположена параллельно оси ординат, и двигаться вдоль оси абсцисс в сторону ее положительного направления. Учитывая введенные ограничения на входные данные, прямая никогда не будет проходить через два события одновременно.&lt;br /&gt;
&lt;br /&gt;
===Статус===&lt;br /&gt;
Назовем статусом множество, в которой содержатся все отрезки, пересекающие нашу сканирующую прямую. Важно, что эти отрезки должны быть упорядочены по возрастанию (или убыванию) координаты их пересечения с прямой. Заметим, что в процессе работы алгоритма отрезки могут добавляться в произвольные места этого упорядоченной множества, удаляться из произвольных мест или меняться местами друг с другом.&lt;br /&gt;
&lt;br /&gt;
===Важная мысль===&lt;br /&gt;
Попробуем найти событие, которое случится раньше всех других, если наша прямая уже пересекает какие-то отрезки. Нам, в данный момент, интересен случай, когда это событие является пересечением отрезков. Важно, что в этом пересечении участвуют два отрезка, которые обязательно являются соседними в нашем статусе.&lt;br /&gt;
&lt;br /&gt;
====Доказательство====&lt;br /&gt;
Предположим, что это не так. Значит, между этими двумя пересекающимися отрезками существует еще хотя бы один. Поскольку эти два отрезка пересекаются, то или третий пересекает перед их пересечением один из них, или пересекается с ними в той же точке. В любом случае, Важная мысль верна&lt;br /&gt;
&lt;br /&gt;
===В итоге===&lt;br /&gt;
Изначально у нас есть только события вида &amp;quot;начался отрезок&amp;quot; и &amp;quot;закончился отрезок&amp;quot;. События вида &amp;quot;пересекаются два отрезка&amp;quot; будут добавляться нами в множество еще не обработанных событий. Соответственно, алгоритм выглядит так: выбираем то событие из множества необработанных, у которого наименьшая координата &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;, обрабатываем, делаем так, пока множество необработанных событий непустое. Плюс, на протяжении всего алгоритма должен поддерживаться следующий инвариант: в множество необработанных событий уже добавлены все пересечения отрезков, которые в текущем статусе текущие.&lt;br /&gt;
&lt;br /&gt;
===Обработка событий===&lt;br /&gt;
====Событие &amp;quot;начало отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка,  между которыми будет находится тот, который начинается. После этого добавляем его в статус на это место и точки его пересечения с соседними добавляем в множество необработанных событий.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;конец отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе отрезок, который заканчивается. Удаляем его оттуда, после чего в множество необработанных событий добавляем точку, в которой пересекаются отрезки, которые были соседями заканчивающегося в старом статусе. Это необходимо, потому что в новом статусе они станут соседними. Заметим, что добавляемое событие может уже находиться в множестве, но нас это совершенно не напрягает.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;пересечение отрезков&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка, которые пересекаются. Меняем их местами (это действительно происходит). После этого добавляем в множество пересечения двух новых пар соседей, которые появились после перестановки пересекшихся отрезков.&lt;br /&gt;
&lt;br /&gt;
==Обработка &amp;quot;нехороших случаев&amp;quot;==&lt;br /&gt;
===Сканирующая точка===&lt;br /&gt;
Решим, для начала, вопрос с вертикальными отрезками. Важно, что заодно пропадет и проблема с обработкой событий, имеющих одинаковую координату по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Слегка поменяем нашу концепцию. Сканирующая прямая теперь становится не совсем прямой. Теперь у нас появляется, скорее, сканирующая точка. Суть изменения в следующем: в случае, если несколько событий попадают на одну вертикальную прямую, мы их обрабатываем в порядке возрастания координаты по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Внимательный читатель сейчас наверное воскликнет: &amp;quot;А как же тогда наш статус? Ведь отрезки не могут пересекать точку!&amp;quot;. Однако и это не является проблемой. Если отрезок, который лежит в статусе, не вертикален, то он сортируется по своей координате &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, в которой он пересекается с вертикальной прямой, проведенной через нашу точку (да, это бывшая сканирующая прямая). А вот если отрезок вертикален, то его параметром является как раз ордината &amp;quot;сканирующей точки&amp;quot;. &amp;lt;s&amp;gt;Если внимательно подумать, то все будет корректно.&amp;lt;/s&amp;gt;Здесь должна быть анимашка, в которой показывается, что все будет корректно.&lt;br /&gt;
&lt;br /&gt;
===Несколько отрезков в одной точке===&lt;br /&gt;
====Первый метод решения проблемы====&lt;br /&gt;
У нас есть упорядоченное множество необработанных событий. Давайте перед добавлением события будем проверять, а нет ли его там. Если оно там уже есть, то события вида &amp;quot;в этой точке перечекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&amp;quot;, превратится в событие вида &amp;quot;в этой точке пересекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;&amp;quot;. В процессе обработки этой точки порядок следования в статусе всех отрезков, пересекающихся в ней, просто инвертируется. Соответственно, проблема решилась.&lt;br /&gt;
&lt;br /&gt;
====Второй метод решения проблемы====&lt;br /&gt;
На самом деле, посмотрим более внимательно, что произойдет в этой точке. Все пересечения всех пар обработаются. Всего таких пар &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt;, где в точке пересекается &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отрезков. Если в некой перестановке делается &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt; элементарных транспозиций, и ни одна из них не повторяется, то перестановка становится инвертированной. Так что, даже если оставить все как есть, то все будет работать. &amp;lt;s&amp;gt;Такие дела.&amp;lt;/s&amp;gt; Здесь тоже должна быть соответствующая анимашка.&lt;br /&gt;
&lt;br /&gt;
===СНМ вместо отрезков===&lt;br /&gt;
'''Внимание! Этот раздел должен интересовать только &amp;lt;s&amp;gt;задротов&amp;lt;/s&amp;gt; любознательных, так как он описывает разбор случая, который нам, по обещанию Ковалева, не встретится.'''&lt;br /&gt;
Нам остался последний сложный случай: наложение двух или более отрезков друг для друга. Давайте теперь вместо просто отрезков будем класть в СНМ следующее: множество отрезков, которые на данном этапе накладываются друг на друга. Понятно, что при добавлении нового отрезка он или создает свое множество, или добавляется в уже существующее. При удалении удаляется из множества, если оно осталось пустым - удаляется и само множество. А при пересечении с другим множеством попарно пересекаются все отрезки из двух множеств. При этом важно, что все отрезки, накладывающиеся друг на друга, должны занимать в статусе одну ячейку, т. е. являться одним множеством.&lt;br /&gt;
&lt;br /&gt;
==Реализация алгоритма==&lt;br /&gt;
===Двоичное дерево поиска в качестве статуса===&lt;br /&gt;
Из определения статуса ясно, какую структуру удобно использовать в качестве статуса: двоичное дерево поиска. В нем удобно делать все необходимые операции, и выполняться они будут за &amp;lt;tex&amp;gt;O(log_2(n))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Реализация множества необработанных событий===&lt;br /&gt;
====Приоритетная очередь====&lt;br /&gt;
Опять же, эта идея возникает в процессе описания этого множества. При этом понятно, что точки сравниваются сначала по абсциссе, в случае равенства - по ординате.&lt;br /&gt;
====Двоичное дерево поиска====&lt;br /&gt;
В принципе, вполне себе вариант реализации упорядоченного множества. Но его стоит использовать только тогда, когда мы хотим рассматривать пересечение нескольких отрезков в одной точке в качестве отдельного случая, а не как несколько попарных пересечений. Заметим, что это существенно усложняет реализацию.&lt;br /&gt;
&lt;br /&gt;
===Наконец, абсолютная точность===&lt;br /&gt;
Заметим, что мы не умеем получать абсолютно точные координаты пересечения двух отрезков. Однако, мы умеем представлять эти координаты в качестве суммы произведений нескольких чисел (просто пересечение прямых и раскрытие скобок в верхней части дроби). А сами координаты нам и не требуются, нам необходимо только уметь сравнивать эти координаты друг с другом. Сравнивать же эти суммы произведений с другими такими же суммами и с обычными числами (в обобщенном представлении тоже такими же суммами) мы тоже умеем. Победа!&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13884</id>
		<title>Алгоритм Бентли-Оттмана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13884"/>
				<updated>2011-12-03T20:45:27Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Бентли-Оттмана(англ. Bentley-Ottmann) - алгоритм, позволяющий по множеству отрезков на плоскости получить множество точек, в которых эти отрезки пересекаются, при этом для каждой точки алгоритм выдает множество отрезков, пересекающихся в ней.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
На плоскости лежит &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; отрезков, каждый из них задан координатами своих концов. Требуется по этим данным определить множество точек, в которых эти отрезки пересекаются. Однако, не всегда координаты точки можно абсолютно точно представить с помощью вещественных типов данных. Поэтому характеризовать каждую точку будем множеством отрезков, которые пересекаются в этой точке.&lt;br /&gt;
&lt;br /&gt;
Для входных данных, представленных на рисунке, ответ будет следующий:[[Файл:pic1.jpg|right|391|thumb|Пример результата работы алгоритма]]&lt;br /&gt;
&lt;br /&gt;
Для упрощения понимания введем два ограничения на входные данные:&lt;br /&gt;
* не существует вертикальных отрезков&lt;br /&gt;
* не существует пары отрезков, имеющих более одной общей точки&lt;br /&gt;
* никакие три отрезка не пересекаются в одной точке&lt;br /&gt;
&lt;br /&gt;
Как обрабатывать эти случаи будет объяснено позднее.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
===Основная идея===&lt;br /&gt;
Алгоритм будет основан на идее сканирующей прямой. Опишем три типа событий, которые мы и будем обрабатывать:&lt;br /&gt;
* начался новый отрезок&lt;br /&gt;
* два отрезка пересеклись&lt;br /&gt;
* отрезок закончился&lt;br /&gt;
&lt;br /&gt;
Сканирующая прямая будет расположена параллельно оси ординат, и двигаться вдоль оси абсцисс в сторону ее положительного направления. Учитывая введенные ограничения на входные данные, прямая никогда не будет проходить через два события одновременно.&lt;br /&gt;
&lt;br /&gt;
===Статус===&lt;br /&gt;
Назовем статусом множество, в которой содержатся все отрезки, пересекающие нашу сканирующую прямую. Важно, что эти отрезки должны быть упорядочены по возрастанию (или убыванию) координаты их пересечения с прямой. Заметим, что в процессе работы алгоритма отрезки могут добавляться в произвольные места этого упорядоченной множества, удаляться из произвольных мест или меняться местами друг с другом.&lt;br /&gt;
&lt;br /&gt;
===Важная мысль===&lt;br /&gt;
Попробуем найти событие, которое случится раньше всех других, если наша прямая уже пересекает какие-то отрезки. Нам, в данный момент, интересен случай, когда это событие является пересечением отрезков. Важно, что в этом пересечении участвуют два отрезка, которые обязательно являются соседними в нашем статусе.&lt;br /&gt;
&lt;br /&gt;
====Доказательство====&lt;br /&gt;
Предположим, что это не так. Значит, между этими двумя пересекающимися отрезками существует еще хотя бы один. Поскольку эти два отрезка пересекаются, то или третий пересекает перед их пересечением один из них, или пересекается с ними в той же точке. В любом случае, Важная мысль верна&lt;br /&gt;
&lt;br /&gt;
===В итоге===&lt;br /&gt;
Изначально у нас есть только события вида &amp;quot;начался отрезок&amp;quot; и &amp;quot;закончился отрезок&amp;quot;. События вида &amp;quot;пересекаются два отрезка&amp;quot; будут добавляться нами в множество еще не обработанных событий. Соответственно, алгоритм выглядит так: выбираем то событие из множества необработанных, у которого наименьшая координата &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;, обрабатываем, делаем так, пока множество необработанных событий непустое. Плюс, на протяжении всего алгоритма должен поддерживаться следующий инвариант: в множество необработанных событий уже добавлены все пересечения отрезков, которые в текущем статусе текущие.&lt;br /&gt;
&lt;br /&gt;
===Обработка событий===&lt;br /&gt;
====Событие &amp;quot;начало отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка,  между которыми будет находится тот, который начинается. После этого добавляем его в статус на это место и точки его пересечения с соседними добавляем в множество необработанных событий.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;конец отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе отрезок, который заканчивается. Удаляем его оттуда, после чего в множество необработанных событий добавляем точку, в которой пересекаются отрезки, которые были соседями заканчивающегося в старом статусе. Это необходимо, потому что в новом статусе они станут соседними. Заметим, что добавляемое событие может уже находиться в множестве, но нас это совершенно не напрягает.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;пересечение отрезков&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка, которые пересекаются. Меняем их местами (это действительно происходит). После этого добавляем в множество пересечения двух новых пар соседей, которые появились после перестановки пересекшихся отрезков.&lt;br /&gt;
&lt;br /&gt;
==Обработка &amp;quot;нехороших случаев&amp;quot;==&lt;br /&gt;
===Сканирующая точка===&lt;br /&gt;
Решим, для начала, вопрос с вертикальными отрезками. Важно, что заодно пропадет и проблема с обработкой событий, имеющих одинаковую координату по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Слегка поменяем нашу концепцию. Сканирующая прямая теперь становится не совсем прямой. Теперь у нас появляется, скорее, сканирующая точка. Суть изменения в следующем: в случае, если несколько событий попадают на одну вертикальную прямую, мы их обрабатываем в порядке возрастания координаты по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Внимательный читатель сейчас наверное воскликнет: &amp;quot;А как же тогда наш статус? Ведь отрезки не могут пересекать точку!&amp;quot;. Однако и это не является проблемой. Если отрезок, который лежит в статусе, не вертикален, то он сортируется по своей координате &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, в которой он пересекается с вертикальной прямой, проведенной через нашу точку (да, это бывшая сканирующая прямая). А вот если отрезок вертикален, то его параметром является как раз ордината &amp;quot;сканирующей точки&amp;quot;. &amp;lt;s&amp;gt;Если внимательно подумать, то все будет корректно.&amp;lt;/s&amp;gt;Здесь должна быть анимашка, в которой показывается, что все будет корректно.&lt;br /&gt;
&lt;br /&gt;
===Несколько отрезков в одной точке===&lt;br /&gt;
====Первый метод решения проблемы====&lt;br /&gt;
У нас есть упорядоченное множество необработанных событий. Давайте перед добавлением события будем проверять, а нет ли его там. Если оно там уже есть, то события вида &amp;quot;в этой точке перечекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&amp;quot;, превратится в событие вида &amp;quot;в этой точке пересекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;&amp;quot;. В процессе обработки этой точки порядок следования в статусе всех отрезков, пересекающихся в ней, просто инвертируется. Соответственно, проблема решилась.&lt;br /&gt;
&lt;br /&gt;
====Второй метод решения проблемы====&lt;br /&gt;
На самом деле, посмотрим более внимательно, что произойдет в этой точке. Все пересечения всех пар обработаются. Всего таких пар &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt;, где в точке пересекается &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отрезков. Если в некой перестановке делается &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt; элементарных транспозиций, и ни одна из них не повторяется, то перестановка становится инвертированной. Так что, даже если оставить все как есть, то все будет работать. &amp;lt;s&amp;gt;Такие дела.&amp;lt;/s&amp;gt; Здесь тоже должна быть соответствующая анимашка.&lt;br /&gt;
&lt;br /&gt;
===СНМ вместо отрезков===&lt;br /&gt;
'''Внимание! Этот раздел должен интересовать только &amp;lt;s&amp;gt;задротов&amp;lt;/s&amp;gt; любознательных, так как он описывает разбор случая, который нам, по обещанию Ковалева, не встретится.'''&lt;br /&gt;
Нам остался последний сложный случай: наложение двух или более отрезков друг для друга. Давайте теперь вместо просто отрезков будем класть в СНМ следующее: множество отрезков, которые на данном этапе накладываются друг на друга. Понятно, что при добавлении нового отрезка он или создает свое множество, или добавляется в уже существующее. При удалении удаляется из множества, если оно осталось пустым - удаляется и само множество. А при пересечении с другим множеством попарно пересекаются все отрезки из двух множеств. При этом важно, что все отрезки, накладывающиеся друг на друга, должны занимать в статусе одну ячейку, т. е. являться одним множеством.&lt;br /&gt;
&lt;br /&gt;
==Реализация алгоритма==&lt;br /&gt;
===Двоичное дерево поиска в качестве статуса===&lt;br /&gt;
Из определения статуса ясно, какую структуру удобно использовать в качестве статуса: двоичное дерево поиска. В нем удобно делать все необходимые операции, и выполняться они будут за &amp;lt;tex&amp;gt;O(log_2(n))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Реализация множества необработанных событий===&lt;br /&gt;
====Приоритетная очередь====&lt;br /&gt;
Опять же, эта идея возникает в процессе описания этого множества. При этом понятно, что точки сравниваются сначала по абсциссе, в случае равенства - по ординате.&lt;br /&gt;
====Двоичное дерево поиска====&lt;br /&gt;
В принципе, вполне себе вариант реализации упорядоченного множества. Но его стоит использовать только тогда, когда мы хотим рассматривать пересечение нескольких отрезков в одной точке в качестве отдельного случая, а не как несколько попарных пересечений. Заметим, что это существенно усложняет реализацию.&lt;br /&gt;
&lt;br /&gt;
===Наконец, абсолютная точность===&lt;br /&gt;
Заметим, что мы не умеем получать абсолютно точные координаты пересечения двух отрезков. Однако, мы умеем представлять эти координаты в качестве суммы произведений нескольких чисел (просто пересечение прямых и раскрытие скобок в верхней части дроби). А сами координаты нам и не требуются, нам необходимо только уметь сравнивать эти координаты друг с другом. Сравнивать же эти суммы произведений с другими такими же суммами и с обычными числами (в обобщенном представлении тоже такими же суммами) мы тоже умеем. Победа!&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13883</id>
		<title>Алгоритм Бентли-Оттмана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13883"/>
				<updated>2011-12-03T20:43:55Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Бентли-Оттмана(англ. Bentley-Ottmann) - алгоритм, позволяющий по множеству отрезков на плоскости получить множество точек, в которых эти отрезки пересекаются, при этом для каждой точки алгоритм выдает множество отрезков, пересекающихся в ней.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
На плоскости лежит &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; отрезков, каждый из них задан координатами своих концов. Требуется по этим данным определить множество точек, в которых эти отрезки пересекаются. Однако, не всегда координаты точки можно абсолютно точно представить с помощью вещественных типов данных. Поэтому характеризовать каждую точку будем множеством отрезков, которые пересекаются в этой точке.&lt;br /&gt;
&lt;br /&gt;
Для входных данных, представленных на рисунке, ответ будет следующий:[[Файл:pic1.jpg]|right|thumb]&lt;br /&gt;
&lt;br /&gt;
Для упрощения понимания введем два ограничения на входные данные:&lt;br /&gt;
* не существует вертикальных отрезков&lt;br /&gt;
* не существует пары отрезков, имеющих более одной общей точки&lt;br /&gt;
* никакие три отрезка не пересекаются в одной точке&lt;br /&gt;
&lt;br /&gt;
Как обрабатывать эти случаи будет объяснено позднее.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
===Основная идея===&lt;br /&gt;
Алгоритм будет основан на идее сканирующей прямой. Опишем три типа событий, которые мы и будем обрабатывать:&lt;br /&gt;
* начался новый отрезок&lt;br /&gt;
* два отрезка пересеклись&lt;br /&gt;
* отрезок закончился&lt;br /&gt;
&lt;br /&gt;
Сканирующая прямая будет расположена параллельно оси ординат, и двигаться вдоль оси абсцисс в сторону ее положительного направления. Учитывая введенные ограничения на входные данные, прямая никогда не будет проходить через два события одновременно.&lt;br /&gt;
&lt;br /&gt;
===Статус===&lt;br /&gt;
Назовем статусом множество, в которой содержатся все отрезки, пересекающие нашу сканирующую прямую. Важно, что эти отрезки должны быть упорядочены по возрастанию (или убыванию) координаты их пересечения с прямой. Заметим, что в процессе работы алгоритма отрезки могут добавляться в произвольные места этого упорядоченной множества, удаляться из произвольных мест или меняться местами друг с другом.&lt;br /&gt;
&lt;br /&gt;
===Важная мысль===&lt;br /&gt;
Попробуем найти событие, которое случится раньше всех других, если наша прямая уже пересекает какие-то отрезки. Нам, в данный момент, интересен случай, когда это событие является пересечением отрезков. Важно, что в этом пересечении участвуют два отрезка, которые обязательно являются соседними в нашем статусе.&lt;br /&gt;
&lt;br /&gt;
====Доказательство====&lt;br /&gt;
Предположим, что это не так. Значит, между этими двумя пересекающимися отрезками существует еще хотя бы один. Поскольку эти два отрезка пересекаются, то или третий пересекает перед их пересечением один из них, или пересекается с ними в той же точке. В любом случае, Важная мысль верна&lt;br /&gt;
&lt;br /&gt;
===В итоге===&lt;br /&gt;
Изначально у нас есть только события вида &amp;quot;начался отрезок&amp;quot; и &amp;quot;закончился отрезок&amp;quot;. События вида &amp;quot;пересекаются два отрезка&amp;quot; будут добавляться нами в множество еще не обработанных событий. Соответственно, алгоритм выглядит так: выбираем то событие из множества необработанных, у которого наименьшая координата &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;, обрабатываем, делаем так, пока множество необработанных событий непустое. Плюс, на протяжении всего алгоритма должен поддерживаться следующий инвариант: в множество необработанных событий уже добавлены все пересечения отрезков, которые в текущем статусе текущие.&lt;br /&gt;
&lt;br /&gt;
===Обработка событий===&lt;br /&gt;
====Событие &amp;quot;начало отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка,  между которыми будет находится тот, который начинается. После этого добавляем его в статус на это место и точки его пересечения с соседними добавляем в множество необработанных событий.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;конец отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе отрезок, который заканчивается. Удаляем его оттуда, после чего в множество необработанных событий добавляем точку, в которой пересекаются отрезки, которые были соседями заканчивающегося в старом статусе. Это необходимо, потому что в новом статусе они станут соседними. Заметим, что добавляемое событие может уже находиться в множестве, но нас это совершенно не напрягает.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;пересечение отрезков&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка, которые пересекаются. Меняем их местами (это действительно происходит). После этого добавляем в множество пересечения двух новых пар соседей, которые появились после перестановки пересекшихся отрезков.&lt;br /&gt;
&lt;br /&gt;
==Обработка &amp;quot;нехороших случаев&amp;quot;==&lt;br /&gt;
===Сканирующая точка===&lt;br /&gt;
Решим, для начала, вопрос с вертикальными отрезками. Важно, что заодно пропадет и проблема с обработкой событий, имеющих одинаковую координату по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Слегка поменяем нашу концепцию. Сканирующая прямая теперь становится не совсем прямой. Теперь у нас появляется, скорее, сканирующая точка. Суть изменения в следующем: в случае, если несколько событий попадают на одну вертикальную прямую, мы их обрабатываем в порядке возрастания координаты по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Внимательный читатель сейчас наверное воскликнет: &amp;quot;А как же тогда наш статус? Ведь отрезки не могут пересекать точку!&amp;quot;. Однако и это не является проблемой. Если отрезок, который лежит в статусе, не вертикален, то он сортируется по своей координате &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, в которой он пересекается с вертикальной прямой, проведенной через нашу точку (да, это бывшая сканирующая прямая). А вот если отрезок вертикален, то его параметром является как раз ордината &amp;quot;сканирующей точки&amp;quot;. &amp;lt;s&amp;gt;Если внимательно подумать, то все будет корректно.&amp;lt;/s&amp;gt;Здесь должна быть анимашка, в которой показывается, что все будет корректно.&lt;br /&gt;
&lt;br /&gt;
===Несколько отрезков в одной точке===&lt;br /&gt;
====Первый метод решения проблемы====&lt;br /&gt;
У нас есть упорядоченное множество необработанных событий. Давайте перед добавлением события будем проверять, а нет ли его там. Если оно там уже есть, то события вида &amp;quot;в этой точке перечекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&amp;quot;, превратится в событие вида &amp;quot;в этой точке пересекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;&amp;quot;. В процессе обработки этой точки порядок следования в статусе всех отрезков, пересекающихся в ней, просто инвертируется. Соответственно, проблема решилась.&lt;br /&gt;
&lt;br /&gt;
====Второй метод решения проблемы====&lt;br /&gt;
На самом деле, посмотрим более внимательно, что произойдет в этой точке. Все пересечения всех пар обработаются. Всего таких пар &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt;, где в точке пересекается &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отрезков. Если в некой перестановке делается &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt; элементарных транспозиций, и ни одна из них не повторяется, то перестановка становится инвертированной. Так что, даже если оставить все как есть, то все будет работать. &amp;lt;s&amp;gt;Такие дела.&amp;lt;/s&amp;gt; Здесь тоже должна быть соответствующая анимашка.&lt;br /&gt;
&lt;br /&gt;
===СНМ вместо отрезков===&lt;br /&gt;
'''Внимание! Этот раздел должен интересовать только &amp;lt;s&amp;gt;задротов&amp;lt;/s&amp;gt; любознательных, так как он описывает разбор случая, который нам, по обещанию Ковалева, не встретится.'''&lt;br /&gt;
Нам остался последний сложный случай: наложение двух или более отрезков друг для друга. Давайте теперь вместо просто отрезков будем класть в СНМ следующее: множество отрезков, которые на данном этапе накладываются друг на друга. Понятно, что при добавлении нового отрезка он или создает свое множество, или добавляется в уже существующее. При удалении удаляется из множества, если оно осталось пустым - удаляется и само множество. А при пересечении с другим множеством попарно пересекаются все отрезки из двух множеств. При этом важно, что все отрезки, накладывающиеся друг на друга, должны занимать в статусе одну ячейку, т. е. являться одним множеством.&lt;br /&gt;
&lt;br /&gt;
==Реализация алгоритма==&lt;br /&gt;
===Двоичное дерево поиска в качестве статуса===&lt;br /&gt;
Из определения статуса ясно, какую структуру удобно использовать в качестве статуса: двоичное дерево поиска. В нем удобно делать все необходимые операции, и выполняться они будут за &amp;lt;tex&amp;gt;O(log_2(n))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Реализация множества необработанных событий===&lt;br /&gt;
====Приоритетная очередь====&lt;br /&gt;
Опять же, эта идея возникает в процессе описания этого множества. При этом понятно, что точки сравниваются сначала по абсциссе, в случае равенства - по ординате.&lt;br /&gt;
====Двоичное дерево поиска====&lt;br /&gt;
В принципе, вполне себе вариант реализации упорядоченного множества. Но его стоит использовать только тогда, когда мы хотим рассматривать пересечение нескольких отрезков в одной точке в качестве отдельного случая, а не как несколько попарных пересечений. Заметим, что это существенно усложняет реализацию.&lt;br /&gt;
&lt;br /&gt;
===Наконец, абсолютная точность===&lt;br /&gt;
Заметим, что мы не умеем получать абсолютно точные координаты пересечения двух отрезков. Однако, мы умеем представлять эти координаты в качестве суммы произведений нескольких чисел (просто пересечение прямых и раскрытие скобок в верхней части дроби). А сами координаты нам и не требуются, нам необходимо только уметь сравнивать эти координаты друг с другом. Сравнивать же эти суммы произведений с другими такими же суммами и с обычными числами (в обобщенном представлении тоже такими же суммами) мы тоже умеем. Победа!&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13882</id>
		<title>Алгоритм Бентли-Оттмана</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%B5%D0%BD%D1%82%D0%BB%D0%B8-%D0%9E%D1%82%D1%82%D0%BC%D0%B0%D0%BD%D0%B0&amp;diff=13882"/>
				<updated>2011-12-03T20:38:43Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Бентли-Оттмана(англ. Bentley-Ottmann) - алгоритм, позволяющий по множеству отрезков на плоскости получить множество точек, в которых эти отрезки пересекаются, при этом для каждой точки алгоритм выдает множество отрезков, пересекающихся в ней.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
На плоскости лежит &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; отрезков, каждый из них задан координатами своих концов. Требуется по этим данным определить множество точек, в которых эти отрезки пересекаются. Однако, не всегда координаты точки можно абсолютно точно представить с помощью вещественных типов данных. Поэтому характеризовать каждую точку будем множеством отрезков, которые пересекаются в этой точке.&lt;br /&gt;
&lt;br /&gt;
Для входных данных, представленных на рисунке, ответ будет следующий:[[Файл:pic1.jpg]]&lt;br /&gt;
&lt;br /&gt;
Для упрощения понимания введем два ограничения на входные данные:&lt;br /&gt;
* не существует вертикальных отрезков&lt;br /&gt;
* не существует пары отрезков, имеющих более одной общей точки&lt;br /&gt;
* никакие три отрезка не пересекаются в одной точке&lt;br /&gt;
&lt;br /&gt;
Как обрабатывать эти случаи будет объяснено позднее.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
===Основная идея===&lt;br /&gt;
Алгоритм будет основан на идее сканирующей прямой. Опишем три типа событий, которые мы и будем обрабатывать:&lt;br /&gt;
* начался новый отрезок&lt;br /&gt;
* два отрезка пересеклись&lt;br /&gt;
* отрезок закончился&lt;br /&gt;
&lt;br /&gt;
Сканирующая прямая будет расположена параллельно оси ординат, и двигаться вдоль оси абсцисс в сторону ее положительного направления. Учитывая введенные ограничения на входные данные, прямая никогда не будет проходить через два события одновременно.&lt;br /&gt;
&lt;br /&gt;
===Статус===&lt;br /&gt;
Назовем статусом множество, в которой содержатся все отрезки, пересекающие нашу сканирующую прямую. Важно, что эти отрезки должны быть упорядочены по возрастанию (или убыванию) координаты их пересечения с прямой. Заметим, что в процессе работы алгоритма отрезки могут добавляться в произвольные места этого упорядоченной множества, удаляться из произвольных мест или меняться местами друг с другом.&lt;br /&gt;
&lt;br /&gt;
===Важная мысль===&lt;br /&gt;
Попробуем найти событие, которое случится раньше всех других, если наша прямая уже пересекает какие-то отрезки. Нам, в данный момент, интересен случай, когда это событие является пересечением отрезков. Важно, что в этом пересечении участвуют два отрезка, которые обязательно являются соседними в нашем статусе.&lt;br /&gt;
&lt;br /&gt;
====Доказательство====&lt;br /&gt;
Предположим, что это не так. Значит, между этими двумя пересекающимися отрезками существует еще хотя бы один. Поскольку эти два отрезка пересекаются, то или третий пересекает перед их пересечением один из них, или пересекается с ними в той же точке. В любом случае, Важная мысль верна&lt;br /&gt;
&lt;br /&gt;
===В итоге===&lt;br /&gt;
Изначально у нас есть только события вида &amp;quot;начался отрезок&amp;quot; и &amp;quot;закончился отрезок&amp;quot;. События вида &amp;quot;пересекаются два отрезка&amp;quot; будут добавляться нами в множество еще не обработанных событий. Соответственно, алгоритм выглядит так: выбираем то событие из множества необработанных, у которого наименьшая координата &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;, обрабатываем, делаем так, пока множество необработанных событий непустое. Плюс, на протяжении всего алгоритма должен поддерживаться следующий инвариант: в множество необработанных событий уже добавлены все пересечения отрезков, которые в текущем статусе текущие.&lt;br /&gt;
&lt;br /&gt;
===Обработка событий===&lt;br /&gt;
====Событие &amp;quot;начало отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка,  между которыми будет находится тот, который начинается. После этого добавляем его в статус на это место и точки его пересечения с соседними добавляем в множество необработанных событий.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;конец отрезка&amp;quot;====&lt;br /&gt;
Находим в статусе отрезок, который заканчивается. Удаляем его оттуда, после чего в множество необработанных событий добавляем точку, в которой пересекаются отрезки, которые были соседями заканчивающегося в старом статусе. Это необходимо, потому что в новом статусе они станут соседними. Заметим, что добавляемое событие может уже находиться в множестве, но нас это совершенно не напрягает.&lt;br /&gt;
&lt;br /&gt;
====Событие &amp;quot;пересечение отрезков&amp;quot;====&lt;br /&gt;
Находим в статусе два отрезка, которые пересекаются. Меняем их местами (это действительно происходит). После этого добавляем в множество пересечения двух новых пар соседей, которые появились после перестановки пересекшихся отрезков.&lt;br /&gt;
&lt;br /&gt;
==Обработка &amp;quot;нехороших случаев&amp;quot;==&lt;br /&gt;
===Сканирующая точка===&lt;br /&gt;
Решим, для начала, вопрос с вертикальными отрезками. Важно, что заодно пропадет и проблема с обработкой событий, имеющих одинаковую координату по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Слегка поменяем нашу концепцию. Сканирующая прямая теперь становится не совсем прямой. Теперь у нас появляется, скорее, сканирующая точка. Суть изменения в следующем: в случае, если несколько событий попадают на одну вертикальную прямую, мы их обрабатываем в порядке возрастания координаты по оси &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Внимательный читатель сейчас наверное воскликнет: &amp;quot;А как же тогда наш статус? Ведь отрезки не могут пересекать точку!&amp;quot;. Однако и это не является проблемой. Если отрезок, который лежит в статусе, не вертикален, то он сортируется по своей координате &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, в которой он пересекается с вертикальной прямой, проведенной через нашу точку (да, это бывшая сканирующая прямая). А вот если отрезок вертикален, то его параметром является как раз ордината &amp;quot;сканирующей точки&amp;quot;. &amp;lt;s&amp;gt;Если внимательно подумать, то все будет корректно.&amp;lt;/s&amp;gt;Здесь должна быть анимашка, в которой показывается, что все будет корректно.&lt;br /&gt;
&lt;br /&gt;
===Несколько отрезков в одной точке===&lt;br /&gt;
====Первый метод решения проблемы====&lt;br /&gt;
У нас есть упорядоченное множество необработанных событий. Давайте перед добавлением события будем проверять, а нет ли его там. Если оно там уже есть, то события вида &amp;quot;в этой точке перечекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt;&amp;quot;, превратится в событие вида &amp;quot;в этой точке пересекаются отрезки &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;&amp;quot;. В процессе обработки этой точки порядок следования в статусе всех отрезков, пересекающихся в ней, просто инвертируется. Соответственно, проблема решилась.&lt;br /&gt;
&lt;br /&gt;
====Второй метод решения проблемы====&lt;br /&gt;
На самом деле, посмотрим более внимательно, что произойдет в этой точке. Все пересечения всех пар обработаются. Всего таких пар &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt;, где в точке пересекается &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; отрезков. Если в некой перестановке делается &amp;lt;tex&amp;gt;k^2&amp;lt;/tex&amp;gt; элементарных транспозиций, и ни одна из них не повторяется, то перестановка становится инвертированной. Так что, даже если оставить все как есть, то все будет работать. &amp;lt;s&amp;gt;Такие дела.&amp;lt;/s&amp;gt; Здесь тоже должна быть соответствующая анимашка.&lt;br /&gt;
&lt;br /&gt;
===СНМ вместо отрезков===&lt;br /&gt;
'''Внимание! Этот раздел должен интересовать только &amp;lt;s&amp;gt;задротов&amp;lt;/s&amp;gt; любознательных, так как он описывает разбор случая, который нам, по обещанию Ковалева, не встретится.'''&lt;br /&gt;
Нам остался последний сложный случай: наложение двух или более отрезков друг для друга. Давайте теперь вместо просто отрезков будем класть в СНМ следующее: множество отрезков, которые на данном этапе накладываются друг на друга. Понятно, что при добавлении нового отрезка он или создает свое множество, или добавляется в уже существующее. При удалении удаляется из множества, если оно осталось пустым - удаляется и само множество. А при пересечении с другим множеством попарно пересекаются все отрезки из двух множеств. При этом важно, что все отрезки, накладывающиеся друг на друга, должны занимать в статусе одну ячейку, т. е. являться одним множеством.&lt;br /&gt;
&lt;br /&gt;
==Реализация алгоритма==&lt;br /&gt;
===Двоичное дерево поиска в качестве статуса===&lt;br /&gt;
Из определения статуса ясно, какую структуру удобно использовать в качестве статуса: двоичное дерево поиска. В нем удобно делать все необходимые операции, и выполняться они будут за &amp;lt;tex&amp;gt;O(log_2(n))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Реализация множества необработанных событий===&lt;br /&gt;
====Приоритетная очередь====&lt;br /&gt;
Опять же, эта идея возникает в процессе описания этого множества. При этом понятно, что точки сравниваются сначала по абсциссе, в случае равенства - по ординате.&lt;br /&gt;
====Двоичное дерево поиска====&lt;br /&gt;
В принципе, вполне себе вариант реализации упорядоченного множества. Но его стоит использовать только тогда, когда мы хотим рассматривать пересечение нескольких отрезков в одной точке в качестве отдельного случая, а не как несколько попарных пересечений. Заметим, что это существенно усложняет реализацию.&lt;br /&gt;
&lt;br /&gt;
===Наконец, абсолютная точность===&lt;br /&gt;
Заметим, что мы не умеем получать абсолютно точные координаты пересечения двух отрезков. Однако, мы умеем представлять эти координаты в качестве суммы произведений нескольких чисел (просто пересечение прямых и раскрытие скобок в верхней части дроби). А сами координаты нам и не требуются, нам необходимо только уметь сравнивать эти координаты друг с другом. Сравнивать же эти суммы произведений с другими такими же суммами и с обычными числами (в обобщенном представлении тоже такими же суммами) мы тоже умеем. Победа!&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Pic1.jpg&amp;diff=13881</id>
		<title>Файл:Pic1.jpg</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Pic1.jpg&amp;diff=13881"/>
				<updated>2011-12-03T20:37:52Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: Пример к статье про Бентли-Оттмана&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пример к статье про Бентли-Оттмана&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9264</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9264"/>
				<updated>2011-06-07T19:23:05Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: /* Постановка задачи */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope''' (''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;: '''количество вершин в поддереве нашей вершины'''(в поддерево включается и сама вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: '''split''' {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и '''merge''' {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и слияние двух любых деревьев.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура '''split''' запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин. Также известно, что в левом поддереве вершины находится &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; вершин, а в правом &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;. Рассмотрим сначала два тривиальных случая. Первый: &amp;lt;tex&amp;gt;l = t&amp;lt;/tex&amp;gt;. В этом случае процедура '''split''' должна просто пометить, что у корня больше нет левого сына, и вернуть его бывшего левого сына в качестве левого ответа, а сам корень {{---}} в качестве правого. Второй случай (&amp;lt;tex&amp;gt;t = l + 1&amp;lt;/tex&amp;gt;) рассматривается аналогично. Следующий случай не так тривиален: &amp;lt;tex&amp;gt;t &amp;lt; l&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру '''split''' от левого сына с тем же параметром &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, и левая часть сына станет левым ответом нашей процедуры, а правая часть станет левым сыном корня, после чего корень станет правым ответом. Случай &amp;lt;tex&amp;gt;t &amp;gt; l + 1&amp;lt;/tex&amp;gt; рассматривается аналогично, с той лишь разницей, что от правого сына отрезается &amp;lt;tex&amp;gt;t - l - 1&amp;lt;/tex&amp;gt; вершин.&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из реализаций процедуры '''merge'''. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры '''merge''' для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности значений &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих значений заключается в том, что после любого действия с детьми вершины нужно записать в ее поле &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; сумму этих значений в ее новых детях, увеличенную на единицу.&lt;br /&gt;
&lt;br /&gt;
==Применение описанного дерева==&lt;br /&gt;
Что же мы получили? У нас есть структура, от которой можно отрезать слева кусок произвольной длины и слить два любых куска в один в нужном порядке. Теперь мы можем:&lt;br /&gt;
* вставить элемент в любое место (отрежем нужное количество слева, сольем левое дерево с деревом из одного добавленного элемента и результат {{---}} с правым деревом)&lt;br /&gt;
* переставить любой кусок массива куда угодно (сделаем нужные разрезы и слияния в правильном порядке)&lt;br /&gt;
* совершать групповые операции с элементами. Вспомним реализацию таких операций в дереве отрезков и поймем, что ничего не помешает нам сделать то же самое с описанным деревом. В групповые операции включается, естественно, и взятие функции от отрезка.&lt;br /&gt;
* сделав на одном исходном массиве два дерева из элементов разной четности, можно решить задачу про смену мест четных и нечетных на отрезке (одно из домашних заданий)&lt;br /&gt;
* повелевать миром&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9263</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9263"/>
				<updated>2011-06-07T19:22:39Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: /* Поддержание корректности ключей X */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;: '''количество вершин в поддереве нашей вершины'''(в поддерево включается и сама вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: '''split''' {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и '''merge''' {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и слияние двух любых деревьев.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура '''split''' запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин. Также известно, что в левом поддереве вершины находится &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; вершин, а в правом &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;. Рассмотрим сначала два тривиальных случая. Первый: &amp;lt;tex&amp;gt;l = t&amp;lt;/tex&amp;gt;. В этом случае процедура '''split''' должна просто пометить, что у корня больше нет левого сына, и вернуть его бывшего левого сына в качестве левого ответа, а сам корень {{---}} в качестве правого. Второй случай (&amp;lt;tex&amp;gt;t = l + 1&amp;lt;/tex&amp;gt;) рассматривается аналогично. Следующий случай не так тривиален: &amp;lt;tex&amp;gt;t &amp;lt; l&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру '''split''' от левого сына с тем же параметром &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, и левая часть сына станет левым ответом нашей процедуры, а правая часть станет левым сыном корня, после чего корень станет правым ответом. Случай &amp;lt;tex&amp;gt;t &amp;gt; l + 1&amp;lt;/tex&amp;gt; рассматривается аналогично, с той лишь разницей, что от правого сына отрезается &amp;lt;tex&amp;gt;t - l - 1&amp;lt;/tex&amp;gt; вершин.&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из реализаций процедуры '''merge'''. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры '''merge''' для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности значений &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих значений заключается в том, что после любого действия с детьми вершины нужно записать в ее поле &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; сумму этих значений в ее новых детях, увеличенную на единицу.&lt;br /&gt;
&lt;br /&gt;
==Применение описанного дерева==&lt;br /&gt;
Что же мы получили? У нас есть структура, от которой можно отрезать слева кусок произвольной длины и слить два любых куска в один в нужном порядке. Теперь мы можем:&lt;br /&gt;
* вставить элемент в любое место (отрежем нужное количество слева, сольем левое дерево с деревом из одного добавленного элемента и результат {{---}} с правым деревом)&lt;br /&gt;
* переставить любой кусок массива куда угодно (сделаем нужные разрезы и слияния в правильном порядке)&lt;br /&gt;
* совершать групповые операции с элементами. Вспомним реализацию таких операций в дереве отрезков и поймем, что ничего не помешает нам сделать то же самое с описанным деревом. В групповые операции включается, естественно, и взятие функции от отрезка.&lt;br /&gt;
* сделав на одном исходном массиве два дерева из элементов разной четности, можно решить задачу про смену мест четных и нечетных на отрезке (одно из домашних заданий)&lt;br /&gt;
* повелевать миром&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9261</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9261"/>
				<updated>2011-06-07T19:21:20Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;: '''количество вершин в поддереве нашей вершины'''(в поддерево включается и сама вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: '''split''' {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и '''merge''' {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и слияние двух любых деревьев.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура '''split''' запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин. Также известно, что в левом поддереве вершины находится &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; вершин, а в правом &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;. Рассмотрим сначала два тривиальных случая. Первый: &amp;lt;tex&amp;gt;l = t&amp;lt;/tex&amp;gt;. В этом случае процедура '''split''' должна просто пометить, что у корня больше нет левого сына, и вернуть его бывшего левого сына в качестве левого ответа, а сам корень {{---}} в качестве правого. Второй случай (&amp;lt;tex&amp;gt;t = l + 1&amp;lt;/tex&amp;gt;) рассматривается аналогично. Следующий случай не так тривиален: &amp;lt;tex&amp;gt;t &amp;lt; l&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру '''split''' от левого сына с тем же параметром &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, и левая часть сына станет левым ответом нашей процедуры, а правая часть станет левым сыном корня, после чего корень станет правым ответом. Случай &amp;lt;tex&amp;gt;t &amp;gt; l + 1&amp;lt;/tex&amp;gt; рассматривается аналогично, с той лишь разницей, что от правого сына отрезается &amp;lt;tex&amp;gt;t - l - 1&amp;lt;/tex&amp;gt; вершин.&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из реализаций процедуры '''merge'''. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры '''merge''' для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности ключей &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих ключей заключается в том, что после любого действия с детьми вершины нужно записать в ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сумму этих ключей в ее новых детях, увеличенную на единицу.&lt;br /&gt;
&lt;br /&gt;
==Применение описанного дерева==&lt;br /&gt;
Что же мы получили? У нас есть структура, от которой можно отрезать слева кусок произвольной длины и слить два любых куска в один в нужном порядке. Теперь мы можем:&lt;br /&gt;
* вставить элемент в любое место (отрежем нужное количество слева, сольем левое дерево с деревом из одного добавленного элемента и результат {{---}} с правым деревом)&lt;br /&gt;
* переставить любой кусок массива куда угодно (сделаем нужные разрезы и слияния в правильном порядке)&lt;br /&gt;
* совершать групповые операции с элементами. Вспомним реализацию таких операций в дереве отрезков и поймем, что ничего не помешает нам сделать то же самое с описанным деревом. В групповые операции включается, естественно, и взятие функции от отрезка.&lt;br /&gt;
* сделав на одном исходном массиве два дерева из элементов разной четности, можно решить задачу про смену мест четных и нечетных на отрезке (одно из домашних заданий)&lt;br /&gt;
* повелевать миром&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9259</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9259"/>
				<updated>2011-06-07T19:13:34Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных ''[[Саморасширяющийся массив|вектор]]''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую ''Декартово дерево по неявному ключу'', или же ''rope'' (''англ.веревка'').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, ''[[Декартово дерево]]'' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: ''количество элементов в нашей структуре, находящихся левее нашего элемента''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;: ''количество вершин в поддереве нашей вершины''(в поддерево включается и сама вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: ''split'' {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и ''merge'' {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и слияние двух любых деревьев.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура ''split'' запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин. Также известно, что в левом поддереве вершины находится &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; вершин, а в правом &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;. Рассмотрим сначала два тривиальных случая. Первый: &amp;lt;tex&amp;gt;l = t&amp;lt;/tex&amp;gt;. В этом случае процедура ''split'' должна просто пометить, что у корня больше нет левого сына, и вернуть его бывшего левого сына в качестве левого ответа, а сам корень {{---}} в качестве правого. Второй крайний случай (&amp;lt;tex&amp;gt;t = l + 1&amp;lt;/tex&amp;gt;) рассматривается аналогично. Следующий случай не так тривиален: &amp;lt;tex&amp;gt;t &amp;lt; l&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру ''split'' от левого сына с тем же параметром &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, и левая часть сына станет левым ответом нашей процедуры, а правая часть станет левым сыном корня, после чего корень станет правым ответом. Случай &amp;lt;tex&amp;gt;t &amp;gt; l + 1&amp;lt;/tex&amp;gt; рассматривается аналогично, с той лишь разницей, что от правого сына отрезается &amp;lt;tex&amp;gt;t - l - 1&amp;lt;/tex&amp;gt; вершин.&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из реализаций процедуры ''merge''. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры ''merge'' для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности значений &amp;lt;tex&amp;gt;С&amp;lt;/tex&amp;gt;===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих значений заключается в том, что после любого действия с детьми вершины нужно записать в ее поле &amp;lt;tex&amp;gt;С&amp;lt;/tex&amp;gt; сумму этих полей в ее новых детях, увеличенную на единицу.&lt;br /&gt;
&lt;br /&gt;
==Применение описанного дерева==&lt;br /&gt;
Что же мы получили? У нас есть структура, от которой можно отрезать слева кусок произвольной длины и слить два любых куска в один в нужном порядке. Теперь мы можем:&lt;br /&gt;
* вставить элемент в любое место (отрежем нужное количество слева, сольем левое дерево с деревом из одного добавленного элемента и результат {{---}} с правым деревом)&lt;br /&gt;
* переставить любой кусок массива куда угодно (сделаем нужные разрезы и слияния в правильном порядке)&lt;br /&gt;
* совершать групповые операции с элементами. Вспомним реализацию таких операций в дереве отрезков и поймем, что ничего не помешает нам сделать то же самое с описанным деревом. В групповые операции включается, естественно, и взятие функции от отрезка.&lt;br /&gt;
* сделав на одном исходном массиве два дерева из элементов разной четности, можно поизвращаться со сменой мест четных и нечетных на отрезке (одно из домашних заданий)&lt;br /&gt;
* повелевать миром&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9258</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9258"/>
				<updated>2011-06-07T19:11:56Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope''' (''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, ''[[Декартово дерево]]'' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: ''количество элементов в нашей структуре, находящихся левее нашего элемента''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt;: ''количество вершин в поддереве нашей вершины''(в поддерево включается и сама вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: ''split'' {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и ''merge'' {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и слияние двух любых деревьев.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура ''split'' запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин. Также известно, что в левом поддереве вершины находится &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; вершин, а в правом &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;. Рассмотрим сначала два тривиальных случая. Первый: &amp;lt;tex&amp;gt;l = t&amp;lt;/tex&amp;gt;. В этом случае процедура ''split'' должна просто пометить, что у корня больше нет левого сына, и вернуть его бывшего левого сына в качестве левого ответа, а сам корень {{---}} в качестве правого. Второй крайний случай (&amp;lt;tex&amp;gt;t = l + 1&amp;lt;/tex&amp;gt;) рассматривается аналогично. Следующий случай не так тривиален: &amp;lt;tex&amp;gt;t &amp;lt; l&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру ''split'' от левого сына с тем же параметром &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, и левая часть сына станет левым ответом нашей процедуры, а правая часть станет левым сыном корня, после чего корень станет правым ответом. Случай &amp;lt;tex&amp;gt;t &amp;gt; l + 1&amp;lt;/tex&amp;gt; рассматривается аналогично, с той лишь разницей, что от правого сына отрезается &amp;lt;tex&amp;gt;t - l - 1&amp;lt;/tex&amp;gt; вершин.&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из реализаций процедуры ''merge''. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры ''merge'' для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности значений &amp;lt;tex&amp;gt;С&amp;lt;/tex&amp;gt;===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих значений заключается в том, что после любого действия с детьми вершины нужно записать в ее поле &amp;lt;tex&amp;gt;С&amp;lt;/tex&amp;gt; сумму этих полей в ее новых детях, увеличенную на единицу.&lt;br /&gt;
&lt;br /&gt;
==Применение описанного дерева==&lt;br /&gt;
Что же мы получили? У нас есть структура, от которой можно отрезать слева кусок произвольной длины и слить два любых куска в один в нужном порядке. Теперь мы можем:&lt;br /&gt;
* вставить элемент в любое место (отрежем нужное количество слева, сольем левое дерево с деревом из одного добавленного элемента и результат {{---}} с правым деревом)&lt;br /&gt;
* переставить любой кусок массива куда угодно (сделаем нужные разрезы и слияния в правильном порядке)&lt;br /&gt;
* совершать групповые операции с элементами. Вспомним реализацию таких операций в дереве отрезков и поймем, что ничего не помешает нам сделать то же самое с описанным деревом. В групповые операции включается, естественно, и взятие функции от отрезка.&lt;br /&gt;
* сделав на одном исходном массиве два дерева из элементов разной четности, можно поизвращаться со сменой мест четных и нечетных на отрезке (одно из домашних заданий)&lt;br /&gt;
* повелевать миром&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B&amp;diff=9182</id>
		<title>Дискретная математика и алгоритмы</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B&amp;diff=9182"/>
				<updated>2011-06-07T06:13:30Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: /* Деревья поиска */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
== Отношения ==&lt;br /&gt;
*[[Определение отношения]]&lt;br /&gt;
*[[Степень отношений]]&lt;br /&gt;
*[[Рефлексивное отношение|Рефлексивное отношение. Антирефлексивное отношение.]]&lt;br /&gt;
*[[Симметричное отношение]]&lt;br /&gt;
*[[Антисимметричное отношение]]&lt;br /&gt;
*[[Композиция отношений|Композиция отношений. Обратное отношение]]&lt;br /&gt;
*[[Транзитивное отношение]]&lt;br /&gt;
*[[Транзитивное замыкание|Транзитивное замыкание отношения]]&lt;br /&gt;
*[[Алгоритм Флойда — Уоршелла|Алгоритм Флойда-Уоршалла построения транзитивного замыкания отношения]]&lt;br /&gt;
&lt;br /&gt;
== Булевы функции ==&lt;br /&gt;
*[[Определение булевой функции]]&lt;br /&gt;
*[[Примеры булевых функций|Примеры булевых функций: все функции от нуля, одной и двух переменных]]&lt;br /&gt;
*[[Подстановка одной функции в другую, отождествление переменных]]&lt;br /&gt;
*[[Представление функции формулой, полные системы функций]]	&lt;br /&gt;
*[[СДНФ]]&lt;br /&gt;
*[[СКНФ]]&lt;br /&gt;
*[[Полином Жегалкина]]&lt;br /&gt;
*[[Теорема Поста о полной системе функций]]&lt;br /&gt;
*[[Сокращенная и минимальная ДНФ]]&lt;br /&gt;
*[[Минимизация ДНФ с помощью покрытий гиперкуба и карт Карно]]&lt;br /&gt;
*[[Специальные формы КНФ|Специальные формы КНФ: КНФ в форме Хорна и КНФ в форме Крома]]&lt;br /&gt;
*[[Преобразование Мёбиуса для получения коэффициентов полинома Жегалкина]]&lt;br /&gt;
*[[Представление функции класса DM с помощью медианы]]&lt;br /&gt;
*[[Пороговая функция]]&lt;br /&gt;
&lt;br /&gt;
== Схемы из функциональных элементов ==&lt;br /&gt;
*[[Реализация булевой функции схемой из функциональных элементов]]&lt;br /&gt;
*[[Изменение размера оптимальной схемы при переходе к другому базису]]&lt;br /&gt;
*[[Cумматор]]&lt;br /&gt;
*[[Каскадный сумматор]]&lt;br /&gt;
*[[Двоичный каскадный сумматор]]&lt;br /&gt;
*[[Матричный умножитель]]&lt;br /&gt;
*[[Дерево Уоллеса]]&lt;br /&gt;
&lt;br /&gt;
== Представление информации ==&lt;br /&gt;
*[[Кодирование информации]]&lt;br /&gt;
*[[Представление целых чисел: прямой код, код со сдвигом, дополнительный код]]&lt;br /&gt;
*[[Представление вещественных чисел]]&lt;br /&gt;
*[[Представление символов, таблицы кодировок]]&lt;br /&gt;
*[[Алгоритм Хаффмана]]&lt;br /&gt;
&lt;br /&gt;
== Алгоритмы сжатия ==&lt;br /&gt;
*[[Алгоритм LZW]]&lt;br /&gt;
*[[Алгоритмы LZ77 и LZ78]]&lt;br /&gt;
*[[Преобразование Барроуза-Уиллера]]&lt;br /&gt;
*[[Обратное преобразование Барроуза-Уиллера]]&lt;br /&gt;
*[[Преобразование MTF]]&lt;br /&gt;
*[[Расстояние Хэмминга]]&lt;br /&gt;
*[[Избыточное кодирование, код Хэмминга]]&lt;br /&gt;
&lt;br /&gt;
== Комбинаторика ==&lt;br /&gt;
*[[Комбинаторные объекты]]&lt;br /&gt;
*[[Лексикографический порядок]]&lt;br /&gt;
*[[Формула включения-исключения]]&lt;br /&gt;
*[[Генерация комбинаторных объектов в лексикографическом порядке]]&lt;br /&gt;
*[[Получение номера по объекту]]&lt;br /&gt;
*[[Получение объекта по номеру]]&lt;br /&gt;
*[[Получение следующего объекта]]&lt;br /&gt;
*[[Коды Грея]]&lt;br /&gt;
*[[Коды Грея для перестановок]]&lt;br /&gt;
*[[Цепные коды]]&lt;br /&gt;
*[[Действие перестановки на набор из элементов, представление в виде циклов]]&lt;br /&gt;
*[[Метод генерации случайной перестановки, алгоритм Фишера-Йетса]]&lt;br /&gt;
*[[Таблица инверсий]]&lt;br /&gt;
*[[Умножение перестановок, обратная перестановка, группа перестановок]]&lt;br /&gt;
*[[Теорема Кэли]]&lt;br /&gt;
*[[Матричное представление перестановок]]&lt;br /&gt;
*[[Задача о минимуме/максимуме скалярного произведения]]&lt;br /&gt;
*[[Задача о монотонных подпоследовательностях, теорема о связи длины НВП и НУП]]&lt;br /&gt;
*[[Поиск наибольшей возрастающей подпоследовательности и т. д.]]&lt;br /&gt;
*[[Нахождение количества разбиений числа на слагаемые | Нахождение количества разбиений числа на слагаемые. Пентагональная теорема Эйлера]]&lt;br /&gt;
&lt;br /&gt;
== Динамическое программирование ==&lt;br /&gt;
*[[Кратчайший путь в ациклическом графе]]&lt;br /&gt;
*[[Задача о расстановке знаков в выражении]]&lt;br /&gt;
*[[Задача о наибольшей общей подпоследовательности]]&lt;br /&gt;
*[[Задача о перемножении матриц]]&lt;br /&gt;
*[[Задача о наибольшей возрастающей подпоследовательности]]&lt;br /&gt;
*[[Задача о паросочетании максимального веса в дереве, амортизированные оценки для ДП на дереве]]&lt;br /&gt;
*[[Метод четырех русских для умножения матриц]]&lt;br /&gt;
*[[Применение метода четырех русских в задачах ДП на примере задачи о НОП]]&lt;br /&gt;
*[[Задача коммивояжера, ДП по подмножествам]]&lt;br /&gt;
*[[Задача о выводе в контекстно-свободной грамматике, алгоритм Кока-Янгера-Касами]]&lt;br /&gt;
*[[Задача о редакционном расстоянии, алгоритм Левенштейна]]&lt;br /&gt;
*[[Задача об оптимальном префиксном коде с сохранением порядка. Монотонность точки разреза]]&lt;br /&gt;
&lt;br /&gt;
== Теория вероятности ==&lt;br /&gt;
*[[Вероятностное пространство, элементарный исход, событие]]&lt;br /&gt;
*[[Независимые события]]&lt;br /&gt;
*[[Условная вероятность]]&lt;br /&gt;
*[[Формула Байеса]]&lt;br /&gt;
*[[Формула полной вероятности]]&lt;br /&gt;
*[[Дискретная случайная величина]]&lt;br /&gt;
*[[Независимые случайные величины]]&lt;br /&gt;
*[[Линейность математического ожидания]]&lt;br /&gt;
*[[Ковариация случайных величин]]&lt;br /&gt;
*[[Дисперсия случайной величины]]&lt;br /&gt;
*[[Энтропия случайного источника]]&lt;br /&gt;
*[[Симуляция одним распределением другого]]&lt;br /&gt;
*[[Арифметическое кодирование]]&lt;br /&gt;
&lt;br /&gt;
== [[Марковская цепь|Марковские цепи]] ==&lt;br /&gt;
&lt;br /&gt;
* [[Теорема о поглощении]]&lt;br /&gt;
* [[Фундаментальная матрица]]&lt;br /&gt;
* [[Математическое ожидание времени поглощения]]&lt;br /&gt;
* [[Расчет вероятности поглощения в состоянии]]&lt;br /&gt;
* [[Эргодическая марковская цепь]]&lt;br /&gt;
* [[Регулярная марковская цепь]]&lt;br /&gt;
&lt;br /&gt;
== Амортизационный анализ ==&lt;br /&gt;
* [[Амортизационный анализ. Метод предоплаты]]&lt;br /&gt;
* [[Саморасширяющийся массив]]&lt;br /&gt;
* [[Массив с увеличением/уменьшением размера]]&lt;br /&gt;
* [[Стек]]&lt;br /&gt;
* [[Очередь]]&lt;br /&gt;
* [[Список]]&lt;br /&gt;
&lt;br /&gt;
== Приоритетные очереди ==&lt;br /&gt;
* [[Двоичная куча|Двоичная куча]]&lt;br /&gt;
* [[Биномиальная куча|Биномиальная пирамида]]&lt;br /&gt;
&lt;br /&gt;
== Система непересекающихся множеств ==&lt;br /&gt;
* [[СНМ(наивные реализации) | Наивные реализации]]&lt;br /&gt;
* [[СНМ(списки с весовой эвристикой) | Списки с весовой эвристикой]]&lt;br /&gt;
* [[СНМ(реализация с помощью леса корневых деревьев) | Реализация с помощью леса корневых деревьев]]&lt;br /&gt;
* [[Анализ реализации с ранговой эвристикой  | Анализ реализации с ранговой эвристикой]]&lt;br /&gt;
&lt;br /&gt;
== Деревья поиска ==&lt;br /&gt;
* [[Упорядоченное множество]]&lt;br /&gt;
* [[Дерево поиска, наивная реализация]]&lt;br /&gt;
* [[АВЛ-дерево]]&lt;br /&gt;
* [[2-3 дерево]]&lt;br /&gt;
* [[B-дерево]]&lt;br /&gt;
* [[Красно-черное дерево]]&lt;br /&gt;
* [[Декартово дерево]]&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
* [[Декартово дерево по неявному ключу]]&lt;br /&gt;
&lt;br /&gt;
== Дерево отрезков ==&lt;br /&gt;
* [[Статистики на отрезках. Корневая эвристика]]&lt;br /&gt;
* [[Дерево отрезков. Построение]]&lt;br /&gt;
* [[Реализация запроса в дереве отрезков сверху]]&lt;br /&gt;
* [[Реализация запроса в дереве отрезков снизу]]&lt;br /&gt;
* [[Несогласованные поддеревья. Реализация массового обновления]]&lt;br /&gt;
&lt;br /&gt;
== Дерево Фенвика ==&lt;br /&gt;
* [[Дерево Фенвика]]&lt;br /&gt;
* [[Встречное дерево Фенвика]]&lt;br /&gt;
* [[Дерево Фенвика, запрос изменения элемента]]&lt;br /&gt;
* [[Многомерное дерево Фенвика]]&lt;br /&gt;
&lt;br /&gt;
== Хеширование ==&lt;br /&gt;
* [[Хеширование]]&lt;br /&gt;
* [[Различные алгоритмы хеширования]]&lt;br /&gt;
* [[Открытое и закрытое хеширование]]&lt;br /&gt;
* [[Поиск свободного места при закрытом хешировании]]&lt;br /&gt;
* [[Хеширование кукушки]]&lt;br /&gt;
* [[Двойное хеширование]]&lt;br /&gt;
&lt;br /&gt;
== Сортировка ==&lt;br /&gt;
* [[Сортировка пузырьком]]&lt;br /&gt;
* [[Сортировка слиянием]]&lt;br /&gt;
* [[Cортировка слиянием с использованием O(1) дополнительной памяти]]&lt;br /&gt;
* [[Сортировка вставками]]&lt;br /&gt;
* [[Сортировка подсчетом]]&lt;br /&gt;
* [[Сортировка подсчетом сложных объектов]]&lt;br /&gt;
* [[Поиск k-ой порядковой статистики]]&lt;br /&gt;
&lt;br /&gt;
== Сортирующие сети ==&lt;br /&gt;
* [[0-1 принцип | Проверка сети компараторов на то, что она сортирующая. 0-1 принцип]]&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9180</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9180"/>
				<updated>2011-06-07T06:12:04Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину: '''количество вершин в поддереве нашей вершины'''(в поддерево включается и сама вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: '''split''' {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и '''merge''' {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и слияние двух любых деревьев.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура '''split''' запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин. Также известно, что в левом поддереве вершины находится &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; вершин, а в правом &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;. Рассмотрим сначала два тривиальных случая. Первый: &amp;lt;tex&amp;gt;l = t&amp;lt;/tex&amp;gt;. В этом случае процедура '''split''' должна просто пометить, что у корня больше нет левого сына, и вернуть его бывшего левого сына в качестве левого ответа, а сам корень {{---}} в качестве правого. Второй крайний случай (&amp;lt;tex&amp;gt;t = l + 1&amp;lt;/tex&amp;gt;) рассматривается аналогично. Следующий случай не так тривиален: &amp;lt;tex&amp;gt;t &amp;lt; l&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру '''split''' от левого сына с тем же параметром &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, и левая часть сына станет левым ответом нашей процедуры, а правая часть станет левым сыном корня, после чего корень станет правым ответом. Случай &amp;lt;tex&amp;gt;t &amp;gt; l + 1&amp;lt;/tex&amp;gt; рассматривается аналогично, с той лишь разницей, что от правого сына отпиливается &amp;lt;tex&amp;gt;t - l - 1&amp;lt;/tex&amp;gt; вершин.&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из реализаций процедуры '''merge'''. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры '''merge''' для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности ключей &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих ключей заключается в том, что после любого действия с детьми вершины нужно записать в ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сумму этих ключей в ее новых детях, увеличенную на единицу.&lt;br /&gt;
&lt;br /&gt;
==Применение описанного дерева==&lt;br /&gt;
Что же мы получили? У нас есть структура, от которой можно без проблем отрезать слева кусок произвольной длины и слить два любых куска в один в нужном порядке. Теперь мы можем безбоязненно:&lt;br /&gt;
* вставить элемент в любое место (отрежем нужное количество слева, сольем левое дерево с деревом из одного добавленного элемента и результат {{---}} с правым деревом)&lt;br /&gt;
* переставить любой кусок массива куда угодно (сделаем нужные разрезы и слияния в правильном порядке)&lt;br /&gt;
* совершать групповые операции с элементами. Вспомним реализацию таких операций в дереве отрезков и поймем, что ничего не помешает нам сделать то же самое с описанным деревом. В групповые операции включается, естественно, и взятие функции от отрезка.&lt;br /&gt;
* сделав на одном исходном массиве два дерева из элементов разной четности, можно поизвращаться со сменой мест четных и нечетных на отрезке (одно из домашних заданий)&lt;br /&gt;
* повелевать миром&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9179</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9179"/>
				<updated>2011-06-07T05:47:07Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину: '''количество вершин в поддереве нашей вершины'''(в поддерево включается и сама вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: '''split''' {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и '''merge''' {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и слияние двух любых деревьев.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура '''split''' запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин. Также известно, что в левом поддереве вершины находится &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; вершин, а в правом &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;. Рассмотрим сначала два тривиальных случая. Первый: &amp;lt;tex&amp;gt;l = t&amp;lt;/tex&amp;gt;. В этом случае процедура '''split''' должна просто пометить, что у корня больше нет левого сына, и вернуть его бывшего левого сына в качестве левого ответа, а сам корень {{---}} в качестве правого. Второй крайний случай (&amp;lt;tex&amp;gt;t = l + 1&amp;lt;/tex&amp;gt;) рассматривается аналогично. Следующий случай не так тривиален: &amp;lt;tex&amp;gt;t &amp;lt; l&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру '''split''' от левого сына с тем же параметром &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, и левая часть сына станет левым ответом нашей процедуры, а правая часть станет левым сыном корня, после чего корень станет правым ответом. Случай &amp;lt;tex&amp;gt;t &amp;gt; l + 1&amp;lt;/tex&amp;gt; рассматривается аналогично, с той лишь разницей, что от правого сына отпиливается &amp;lt;tex&amp;gt;t - l - 1&amp;lt;/tex&amp;gt; вершин.&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из реализаций процедуры '''merge'''. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры '''merge''' для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности ключей &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих ключей заключается в том, что после любого действия с детьми вершины нужно записать в ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сумму этих ключей в ее новых детях, увеличенную на единицу.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9176</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=9176"/>
				<updated>2011-06-07T05:32:41Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину: '''количество вершин в поддереве нашей вершины'''(в поддерево включается и сама вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: '''split''' {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и '''merge''' {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и слияние двух любых деревьев.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8252</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8252"/>
				<updated>2011-04-27T06:17:01Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
[[Файл:Tree_1.png|right|250px|thumb|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину: '''количество вершин в поддереве нашей вершины'''(включая и саму нашу вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину и добавив к этой величине количество элементов в её левом поддереве, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Tree_1.png&amp;diff=8251</id>
		<title>Файл:Tree 1.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Tree_1.png&amp;diff=8251"/>
				<updated>2011-04-27T06:15:33Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8250</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8250"/>
				<updated>2011-04-27T05:54:49Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(''англ.'''веревка''''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. &lt;br /&gt;
&lt;br /&gt;
Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется проблема: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;br /&gt;
&lt;br /&gt;
Как же нам быть? Основная идея заключается в том, что такой ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; сам по себе нигде не хранится. Вместо него будем хранить вспомогательную величину: '''количество вершин в поддереве нашей вершины'''(включая и саму нашу вершину). Обратим внимание, что все операции с обычным декартовым деревом делались сверху. Также заметим, что если по пути до некой вершины просуммируем все такие величины в левых поддеревьях, в которые мы не пошли, увеличенные на единицу, то придя в саму вершину, мы получим как раз ее ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8249</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8249"/>
				<updated>2011-04-27T05:44:09Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=30%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(англ.'''веревка''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется две проблемы: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:Q&amp;diff=8248</id>
		<title>Шаблон:Q</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:Q&amp;diff=8248"/>
				<updated>2011-04-27T05:43:19Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: Новая страница: «&amp;lt;table style=&amp;quot;margin:16px auto auto; border-collapse:collapse; background-color:transparent; border-style:none; width:{{{width|{{{w|auto}}}}}};&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td style=&amp;quot;width…»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;table style=&amp;quot;margin:16px auto auto; border-collapse:collapse; background-color:transparent; border-style:none; width:{{{width|{{{w|auto}}}}}};&amp;quot;&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td style=&amp;quot;width:30px; padding-left:25px; vertical-align:top; text-align:left; color:silver; font-size:2.5em; font-family:serif; font-weight:bold;&amp;quot;&amp;gt;{{{qmarkl|«}}}&amp;lt;/td&amp;gt;&amp;lt;td style=&amp;quot;display:block; text-align:{{{text-align|{{{ta|left}}}}}}; font-style:italic;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;p class=&amp;quot;{{#if: {{{pre|{{{p|}}}}}}|pre}}quote&amp;quot;&amp;gt;{{{text|{{{t|{{{1|Текст цитаты}}}}}}}}}&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/td&amp;gt;&amp;lt;td style=&amp;quot;width:30px; padding-right:25px; vertical-align:bottom; text-align:right; color:silver; font-size:2.5em; font-family:serif; font-weight:bold;&amp;quot;&amp;gt;{{{qmarkr|»}}}&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;!-- &lt;br /&gt;
&lt;br /&gt;
Дальше подпись, с пугающим механизмом отключения.&lt;br /&gt;
&lt;br /&gt;
На самом деле всё просто:&lt;br /&gt;
&lt;br /&gt;
Если получаем нуль в первом #ifeq:, то выводим подпись, в этом нам помогает #if:{{{source|{{{s|}}}}}}, который сразу возвращает ноль, если параметры source или s не пусты. Если пусты, то проходит викифицированный механизм &amp;quot;2==noanon OR 2==na OR noanon и na имеют значения&amp;quot; — любое из этих условий даст единичку, то есть подписи не будет.&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;{{#ifeq:{{#if:{{{source|{{{s|}}}}}}|0|{{#expr: {{#ifeq:{{{2|}}}|noanon|1|0}} + {{#ifeq:{{{2|}}}|na|1|0}} + {{#if:{{{noanon|{{{na|}}}}}}|1|0}} }} }}|0|&amp;lt;tr&amp;gt;&amp;lt;td colspan=&amp;quot;3&amp;quot; style=&amp;quot;font-size:80%; line-height:80%; text-align:right; padding: 5px 30px 0;&amp;quot;&amp;gt;— {{{source|{{{s|{{{2|Анонимус}}}}}}}}}&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;}}&lt;br /&gt;
&amp;lt;/table&amp;gt;&amp;lt;noinclude&amp;gt;{{doc}}&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8247</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8247"/>
				<updated>2011-04-27T05:41:30Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Q|width=80%|Декартово дерево правит миром. За логарифм.|Неизвестный автор}}&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(англ.'''веревка''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется две проблемы: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8246</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8246"/>
				<updated>2011-04-27T05:38:09Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Постановка задачи==&lt;br /&gt;
Возьмем структуру данных '''[[Саморасширяющийся массив|вектор]]'''. В её стандартной реализации мы умеем добавить элемент в конец, узнать значение элемента и изменить элемент по номеру, и удалить последний элемент. Расширим круг задач: теперь мы хотим добавлять элемент в любое место (с соответствующим изменением нумерации элементов) и удалять любой элемент (с тем же самым уточнением). Теперь нам нужно придумать структуру, называемую '''Декартово дерево по неявному ключу''', или же '''rope'''(англ.'''веревка''').&lt;br /&gt;
&lt;br /&gt;
==Основная идея==&lt;br /&gt;
Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу. Для решения задачи, поставленной в предыдущей главе, попробуем слегка модифицировать эту структуру. Если конкретнее, то оставим в нем только один ключ - ключ &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;. Вместо второго ключа будем использовать следующую величину: '''количество элементов в нашей структуре, находящихся левее нашего элемента'''. Если проще, то будем считать ключом порядковый номер нашего элемента в дереве, уменьшенный на единицу. Заметим, что при этом сохранится структура [[Дерево_поиска,_наивная_реализация|двоичного дерева поиска]] по этому ключу(т.е. наше модифицированное декартово дерево так и останется декартовым деревом). Однако, с этим подходом появляется две проблемы: наши операции добавления и удаления элемента могут поменять нумерацию, и при наивной реализации на изменение всех ключей потребуется &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} количество элементов в дереве.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8245</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8245"/>
				<updated>2011-04-27T05:17:53Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу.&lt;br /&gt;
&lt;br /&gt;
==Постановка задачи==&lt;br /&gt;
Стандартное декартово дерево (или любое другое сбалансированное дерево поиска, мы будем рассматривать именно это применение декартовых деревьев) позволяет нам совершать практически любые операции, собственно, вставить или удалить элемент. Попробуем расширить список действий, которые мы хотим уметь делать. Основной принцип расширения можно описать так : '''взять элементы с порядковыми номерами от &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; и что-нибудь с ними сделать(вырезать, переставить, добавить ко всем числам на отрезке, развернуть, ...'''.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8244</id>
		<title>Декартово дерево по неявному ключу</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B5%D0%BA%D0%B0%D1%80%D1%82%D0%BE%D0%B2%D0%BE_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE_%D0%BF%D0%BE_%D0%BD%D0%B5%D1%8F%D0%B2%D0%BD%D0%BE%D0%BC%D1%83_%D0%BA%D0%BB%D1%8E%D1%87%D1%83&amp;diff=8244"/>
				<updated>2011-04-27T05:03:15Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: Новая страница: «Напомним, '''Декартово дерево''' {{---}} это структура данных, объединяющая в себе бинарное д…»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Напомним, '''[[Декартово дерево]]''' {{---}} это структура данных, объединяющая в себе бинарное дерево поиска и бинарную кучу.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D1%81%D1%85%D0%BE%D0%B4%D1%8F%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D1%80%D1%8F%D0%B4%D0%BE%D0%B2&amp;diff=7694</id>
		<title>Суммирование расходящихся рядов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D1%81%D1%85%D0%BE%D0%B4%D1%8F%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D1%80%D1%8F%D0%B4%D0%BE%D0%B2&amp;diff=7694"/>
				<updated>2011-02-16T19:41:27Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: Метод Абеля, без доказательства.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Введение ==&lt;br /&gt;
&lt;br /&gt;
Напомним, что имея последовательность суммы вещественных чисел &amp;lt;tex&amp;gt;\{a_n\}&amp;lt;/tex&amp;gt; рядом мы называли символ &amp;lt;tex&amp;gt;\sum\limits_{i = 1}^\infty a_i&amp;lt;/tex&amp;gt;. Ряды можно склажывать и умножать на число. Далее, мы определили &amp;lt;tex&amp;gt;\sum\limits_{i = 1}^\infty a_i = \lim\limits_{n \rightarrow \infty} \sum\limits_{i = 1}^n a_i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы показали, что исходя их этого равенства для сходимости ряда частичных сумм необходимо условие &amp;lt;tex&amp;gt;a_n \longrightarrow 0&amp;lt;/tex&amp;gt;. Например, ряд &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty&amp;lt;/tex&amp;gt; не сходится (не имеет суммы в представленном выше смысле), поскольку &amp;lt;tex&amp;gt;(-1)^n&amp;lt;/tex&amp;gt; предела не имеет.&lt;br /&gt;
&lt;br /&gt;
Во многих задачах математики необходимо символу ряда приписывать некоторое число и называть суммой ряда. Как правило, требуется соблюдение условий, вытекающих из арифметических действий с обычными рядами.&lt;br /&gt;
&lt;br /&gt;
== Правила суммирования ==&lt;br /&gt;
&lt;br /&gt;
Когда пишут &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n = A(F)&amp;lt;/tex&amp;gt;, то говорят, что ряд из &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; имеет сумму &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; по правилу суммирования &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для правил суммирования требуется выполнение некоторых условий.&lt;br /&gt;
&lt;br /&gt;
* Линейность: если ряд из &amp;lt;tex&amp;gt;b_n&amp;lt;/tex&amp;gt; имеет суммой &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; по правилу &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;, то ряд из &amp;lt;tex&amp;gt;\alpha a_n + \beta b_n&amp;lt;/tex&amp;gt; должен по этому правилу иметь суммой &amp;lt;tex&amp;gt;\alpha A + \beta B&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Перманентность (регулярность): если &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n = A&amp;lt;/tex&amp;gt; (ряд имеет сумму в обычном смысле), то &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n = A(F)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Эффективность: должны существовать ряды, которые суммируются с помощью &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;, но не имеют суммы в классическом смысле.&lt;br /&gt;
&lt;br /&gt;
== Метод средних арифметических ==&lt;br /&gt;
&lt;br /&gt;
Ряд &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n&amp;lt;/tex&amp;gt; имеет сумму &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; по методу средних арифметических (обозначают аббревиатурой с.а.), если &amp;lt;tex&amp;gt;S = \lim\limits_{n \rightarrow \infty} \frac 1{n + 1} \sum\limits_{k = 0}^n S_n&amp;lt;/tex&amp;gt;. Как правило, используют обозначение &amp;lt;tex&amp;gt;\sigma_n = \frac 1{n + 1} \sum\limits_{k = 0}^n S_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выясним, что способ удовлетворяет перечисленным выше требованиям. Линейность этого способа очевидна (из арифметики пределов и свойствах сложения конечного числа слагаемых).&lt;br /&gt;
&lt;br /&gt;
Проверим эффективность способа.&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&lt;br /&gt;
Сумма расходящегося ряда &amp;lt;tex&amp;gt;\sum\limits_{k = 0}^\infty (-1)^k&amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt;\frac 12&amp;lt;/tex&amp;gt; по методу средних арифметических.&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;\sigma_{2m + 1} = \frac 1{2m + 1} (S_0 + S_1 + \dots + S_{2m}) = \frac m{2m + 1} \longrightarrow \frac 12&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Аналогично рассматриваем &amp;lt;tex&amp;gt;\sigma_{2m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итого, &amp;lt;tex&amp;gt;\sigma_n \longrightarrow \frac 12&amp;lt;/tex&amp;gt;, и ряд имеет сумму &amp;lt;tex&amp;gt;\frac 12&amp;lt;/tex&amp;gt; по методу средних арифметических.&lt;br /&gt;
}}&lt;br /&gt;
Проверим перманентность. Требуется доказать, что если &amp;lt;tex&amp;gt;S = \lim\limits_{n \rightarrow \infty} S_n&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;S = \lim\limits_{n \rightarrow \infty} \sigma_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Действительно, &amp;lt;tex&amp;gt;S_n = S + \alpha_n&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\alpha_n \longrightarrow 0&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;\sigma_n = S + \frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Требуется доказать, что &amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k \longrightarrow 0&amp;lt;/tex&amp;gt;. Докажем по определению.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим некоторое &amp;lt;tex&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/tex&amp;gt;, подбираем &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt;n \ge N \Rightarrow |\alpha_n| &amp;lt; \varepsilon / 2&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k = \frac 1{n + 1} \sum\limits_{k = 0}^N \alpha_k + \sum\limits_{k = N + 1}^n \alpha_k&amp;lt;/tex&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\left | \frac 1{2n + 1} \sum\limits_{k = 0}^n \alpha_k \right | \le \frac 1{n + 1} \sum\limits_{k = 0}^N |\alpha_k| + \frac {n - N}{n + 1} \varepsilon&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поскольку в первом слагаемом бесконечно малая умножается на константу, то начиная с &amp;lt;tex&amp;gt;N_1&amp;lt;/tex&amp;gt; выполняется &amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n |\alpha_k| &amp;lt; \varepsilon / 2&amp;lt;/tex&amp;gt;. Но, поскольку &amp;lt;tex&amp;gt;\frac {n - N}{n + 1} &amp;lt; 1&amp;lt;/tex&amp;gt;, то, начиная с &amp;lt;tex&amp;gt;N + N_1&amp;lt;/tex&amp;gt; выполняется &amp;lt;tex&amp;gt;\left | \frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k \right | &amp;lt; \varepsilon&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, по определению предела &amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k&amp;lt;/tex&amp;gt; стремится к нулю.&lt;br /&gt;
&lt;br /&gt;
==Метод Абеля==&lt;br /&gt;
&lt;br /&gt;
===Некоторые умозаключения===&lt;br /&gt;
&amp;lt;tex&amp;gt;(n + 1)\sigma_n = S_0 + S_1 + \ldots + S_n&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;n\sigma_n = S_0 + s_1 + \ldots + S_{n - 1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выразим частичные суммы через &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\sigma&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;(n + 1)\sigma_n - n\sigma_{n - 1} = S_n&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;n\sigma_{n - 1} - (n - 1)\sigma_{n - 2} = S_{n - 1}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выразим через это же элемент ряда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;(n + 1)\sigma_n - 2n\sigma_{n - 1} + (n - 1)\sigma_{n - 2} = a_n&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поделим все выражение на &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\frac {a_n}{n} = (1 + \frac {1}{n})\sigma_n - 2\sigma_{n - 1} + (1 - \frac {1}{n})\sigma_{n - 2}&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы знаем, что &amp;lt;tex&amp;gt; \sigma_n\to S &amp;lt;/tex&amp;gt; при &amp;lt;tex&amp;gt; n \to \infty&amp;lt;/tex&amp;gt;. Получается, что &amp;lt;tex&amp;gt; \frac {a_n}{n}\rightarrow 0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Необходимый признак===&lt;br /&gt;
&lt;br /&gt;
Из предыдущего пункта вытекает необходимый признак:&lt;br /&gt;
&lt;br /&gt;
Если ряд суммируется методом средних арифметических&amp;lt;tex dpi&amp;gt;(\exists \lim\limits_{n \to \infty} \sigma_n)&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\frac {a_n}{n} \to 0&amp;lt;/tex&amp;gt;. Однако, существуют ряды, у которых это требование не выполняется. Например: &amp;lt;tex&amp;gt; \sum\limits_{k = 0}^{\infty} (-1)^k(k + 1)&amp;lt;/tex&amp;gt;. Было бы неплохо научиться что-нибудь делать хотя бы с некоторыми такими рядами.&lt;br /&gt;
&lt;br /&gt;
===Метод Абеля===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\sum\limits_{n = 0}^{\infty}a_n&amp;lt;/tex&amp;gt;, пусть &amp;lt;tex&amp;gt; \forall t \in (0; 1) : \sum\limits_{n = 0}^{\infty}a_nt^n = f(t)&amp;lt;/tex&amp;gt;(в классическом смысле). Полагаем &amp;lt;tex&amp;gt; S = \lim\limits_{t \to 1 - 0} f(t)&amp;lt;/tex&amp;gt;(если таковой существует).&lt;br /&gt;
&lt;br /&gt;
{{Определение||definition = &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^{\infty} = S(A)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; {{---}} метод Абеля.}}&lt;br /&gt;
&lt;br /&gt;
===Доказательство правильности===&lt;br /&gt;
&lt;br /&gt;
*Линейность - очевидна из определения.&lt;br /&gt;
&lt;br /&gt;
*Эффективность:&lt;br /&gt;
&lt;br /&gt;
*Перманентность:&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D1%81%D1%85%D0%BE%D0%B4%D1%8F%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D1%80%D1%8F%D0%B4%D0%BE%D0%B2&amp;diff=7693</id>
		<title>Суммирование расходящихся рядов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D1%81%D1%85%D0%BE%D0%B4%D1%8F%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D1%80%D1%8F%D0%B4%D0%BE%D0%B2&amp;diff=7693"/>
				<updated>2011-02-16T18:42:04Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: /* Правила суммирования */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Введение ==&lt;br /&gt;
&lt;br /&gt;
Напомним, что имея последовательность суммы вещественных чисел &amp;lt;tex&amp;gt;\{a_n\}&amp;lt;/tex&amp;gt; рядом мы называли символ &amp;lt;tex&amp;gt;\sum\limits_{i = 1}^\infty a_i&amp;lt;/tex&amp;gt;. Ряды можно склажывать и умножать на число. Далее, мы определили &amp;lt;tex&amp;gt;\sum\limits_{i = 1}^\infty a_i = \lim\limits_{n \rightarrow \infty} \sum\limits_{i = 1}^n a_i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы показали, что исходя их этого равенства для сходимости ряда частичных сумм необходимо условие &amp;lt;tex&amp;gt;a_n \longrightarrow 0&amp;lt;/tex&amp;gt;. Например, ряд &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty&amp;lt;/tex&amp;gt; не сходится (не имеет суммы в представленном выше смысле), поскольку &amp;lt;tex&amp;gt;(-1)^n&amp;lt;/tex&amp;gt; предела не имеет.&lt;br /&gt;
&lt;br /&gt;
Во многих задачах математики необходимо символу ряда приписывать некоторое число и называть суммой ряда. Как правило, требуется соблюдение условий, вытекающих из арифметических действий с обычными рядами.&lt;br /&gt;
&lt;br /&gt;
== Правила суммирования ==&lt;br /&gt;
&lt;br /&gt;
Когда пишут &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n = A(F)&amp;lt;/tex&amp;gt;, то говорят, что ряд из &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; имеет сумму &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; по правилу суммирования &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для правил суммирования требуется выполнение некоторых условий.&lt;br /&gt;
&lt;br /&gt;
* Если ряд из &amp;lt;tex&amp;gt;b_n&amp;lt;/tex&amp;gt; имеет суммой &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; по правилу &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;, то ряд из &amp;lt;tex&amp;gt;\alpha a_n + \beta b_n&amp;lt;/tex&amp;gt; должен по этому правилу иметь суммой &amp;lt;tex&amp;gt;\alpha A + \beta B&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Перманентность (регулярность): если &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n = A&amp;lt;/tex&amp;gt; (ряд имеет сумму в обычном смысле), то &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n = A(F)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Эффективность: должны существовать ряды, которые суммируются с помощью &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;, но не имеют суммы в классическом смысле.&lt;br /&gt;
&lt;br /&gt;
== Метод средних арифметических ==&lt;br /&gt;
&lt;br /&gt;
Ряд &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n&amp;lt;/tex&amp;gt; имеет сумму &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; по методу средних арифметических (обозначают аббревиатурой с.а.), если &amp;lt;tex&amp;gt;S = \lim\limits_{n \rightarrow \infty} \frac 1{n + 1} \sum\limits_{k = 0}^n S_n&amp;lt;/tex&amp;gt;. Как правило, используют обозначение &amp;lt;tex&amp;gt;\sigma_n = \frac 1{n + 1} \sum\limits_{k = 0}^n S_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выясним, что способ удовлетворяет перечисленным выше требованиям. Линейность этого способа очевидна (из арифметики пределов и свойствах сложения конечного числа слагаемых).&lt;br /&gt;
&lt;br /&gt;
Проверим эффективность способа.&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&lt;br /&gt;
Сумма расходящегося ряда &amp;lt;tex&amp;gt;\sum\limits_{k = 0}^\infty (-1)^k&amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt;\frac 12&amp;lt;/tex&amp;gt; по методу средних арифметических.&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;\sigma_{2m + 1} = \frac 1{2m + 1} (S_0 + S_1 + \dots + S_{2m}) = \frac m{2m + 1} \longrightarrow \frac 12&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Аналогично рассматриваем &amp;lt;tex&amp;gt;\sigma_{2m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итого, &amp;lt;tex&amp;gt;\sigma_n \longrightarrow \frac 12&amp;lt;/tex&amp;gt;, и ряд имеет сумму &amp;lt;tex&amp;gt;\frac 12&amp;lt;/tex&amp;gt; по методу средних арифметических.&lt;br /&gt;
}}&lt;br /&gt;
Проверим перманентность. Требуется доказать, что если &amp;lt;tex&amp;gt;S = \lim\limits_{n \rightarrow \infty} S_n&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;S = \lim\limits_{n \rightarrow \infty} \sigma_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Действительно, &amp;lt;tex&amp;gt;S_n = S + \alpha_n&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\alpha_n \longrightarrow 0&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;\sigma_n = S + \frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Требуется доказать, что &amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k \longrightarrow 0&amp;lt;/tex&amp;gt;. Докажем по определению.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим некоторое &amp;lt;tex&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/tex&amp;gt;, подбираем &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt;n \ge N \Rightarrow |\alpha_n| &amp;lt; \varepsilon / 2&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k = \frac 1{n + 1} \sum\limits_{k = 0}^N \alpha_k + \sum\limits_{k = N + 1}^n \alpha_k&amp;lt;/tex&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\left | \frac 1{2n + 1} \sum\limits_{k = 0}^n \alpha_k \right | \le \frac 1{n + 1} \sum\limits_{k = 0}^N |\alpha_k| + \frac {n - N}{n + 1} \varepsilon&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поскольку в первом слагаемом бесконечно малая умножается на константу, то начиная с &amp;lt;tex&amp;gt;N_1&amp;lt;/tex&amp;gt; выполняется &amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n |\alpha_k| &amp;lt; \varepsilon / 2&amp;lt;/tex&amp;gt;. Но, поскольку &amp;lt;tex&amp;gt;\frac {n - N}{n + 1} &amp;lt; 1&amp;lt;/tex&amp;gt;, то, начиная с &amp;lt;tex&amp;gt;N + N_1&amp;lt;/tex&amp;gt; выполняется &amp;lt;tex&amp;gt;\left | \frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k \right | &amp;lt; \varepsilon&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, по определению предела &amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k&amp;lt;/tex&amp;gt; стремится к нулю.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D1%81%D1%85%D0%BE%D0%B4%D1%8F%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D1%80%D1%8F%D0%B4%D0%BE%D0%B2&amp;diff=7692</id>
		<title>Суммирование расходящихся рядов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%80%D0%B0%D1%81%D1%85%D0%BE%D0%B4%D1%8F%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D1%80%D1%8F%D0%B4%D0%BE%D0%B2&amp;diff=7692"/>
				<updated>2011-02-16T18:40:56Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: /* Правила суммирования */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Введение ==&lt;br /&gt;
&lt;br /&gt;
Напомним, что имея последовательность суммы вещественных чисел &amp;lt;tex&amp;gt;\{a_n\}&amp;lt;/tex&amp;gt; рядом мы называли символ &amp;lt;tex&amp;gt;\sum\limits_{i = 1}^\infty a_i&amp;lt;/tex&amp;gt;. Ряды можно склажывать и умножать на число. Далее, мы определили &amp;lt;tex&amp;gt;\sum\limits_{i = 1}^\infty a_i = \lim\limits_{n \rightarrow \infty} \sum\limits_{i = 1}^n a_i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Мы показали, что исходя их этого равенства для сходимости ряда частичных сумм необходимо условие &amp;lt;tex&amp;gt;a_n \longrightarrow 0&amp;lt;/tex&amp;gt;. Например, ряд &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty&amp;lt;/tex&amp;gt; не сходится (не имеет суммы в представленном выше смысле), поскольку &amp;lt;tex&amp;gt;(-1)^n&amp;lt;/tex&amp;gt; предела не имеет.&lt;br /&gt;
&lt;br /&gt;
Во многих задачах математики необходимо символу ряда приписывать некоторое число и называть суммой ряда. Как правило, требуется соблюдение условий, вытекающих из арифметических действий с обычными рядами.&lt;br /&gt;
&lt;br /&gt;
== Правила суммирования ==&lt;br /&gt;
&lt;br /&gt;
Когда пишут &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n = A(F)&amp;lt;/tex&amp;gt;, то говорят, что ряд из &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; имеет сумму &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; по правилу суммирования &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для правил суммирования требуется выполнение некоторых условий.&lt;br /&gt;
&lt;br /&gt;
* Если ряд из &amp;lt;tex&amp;gt;b_n&amp;lt;/tex&amp;gt; имеет суммой &amp;lt;tex&amp;gt;B&amp;lt;/tex&amp;gt; по правилу &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;, то ряд из &amp;lt;tex&amp;gt;\alpha a_n + \beta b_n&amp;lt;/tex&amp;gt; должен по этому правилу иметь суммой &amp;lt;tex&amp;gt;\alpha A + \beta B&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
* Перманентность (регулярность): если &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n = A&amp;lt;/tex&amp;gt; (ряд имеет сумму в обычном смысле), то &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n = A(F)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Эффективность — должны существовать ряды, которые суммируются с помощью &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;, но не имеют суммы в классическом смысле.&lt;br /&gt;
&lt;br /&gt;
== Метод средних арифметических ==&lt;br /&gt;
&lt;br /&gt;
Ряд &amp;lt;tex&amp;gt;\sum\limits_{n = 0}^\infty a_n&amp;lt;/tex&amp;gt; имеет сумму &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; по методу средних арифметических (обозначают аббревиатурой с.а.), если &amp;lt;tex&amp;gt;S = \lim\limits_{n \rightarrow \infty} \frac 1{n + 1} \sum\limits_{k = 0}^n S_n&amp;lt;/tex&amp;gt;. Как правило, используют обозначение &amp;lt;tex&amp;gt;\sigma_n = \frac 1{n + 1} \sum\limits_{k = 0}^n S_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Выясним, что способ удовлетворяет перечисленным выше требованиям. Линейность этого способа очевидна (из арифметики пределов и свойствах сложения конечного числа слагаемых).&lt;br /&gt;
&lt;br /&gt;
Проверим эффективность способа.&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&lt;br /&gt;
Сумма расходящегося ряда &amp;lt;tex&amp;gt;\sum\limits_{k = 0}^\infty (-1)^k&amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt;\frac 12&amp;lt;/tex&amp;gt; по методу средних арифметических.&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;\sigma_{2m + 1} = \frac 1{2m + 1} (S_0 + S_1 + \dots + S_{2m}) = \frac m{2m + 1} \longrightarrow \frac 12&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Аналогично рассматриваем &amp;lt;tex&amp;gt;\sigma_{2m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Итого, &amp;lt;tex&amp;gt;\sigma_n \longrightarrow \frac 12&amp;lt;/tex&amp;gt;, и ряд имеет сумму &amp;lt;tex&amp;gt;\frac 12&amp;lt;/tex&amp;gt; по методу средних арифметических.&lt;br /&gt;
}}&lt;br /&gt;
Проверим перманентность. Требуется доказать, что если &amp;lt;tex&amp;gt;S = \lim\limits_{n \rightarrow \infty} S_n&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;S = \lim\limits_{n \rightarrow \infty} \sigma_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Действительно, &amp;lt;tex&amp;gt;S_n = S + \alpha_n&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\alpha_n \longrightarrow 0&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;\sigma_n = S + \frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Требуется доказать, что &amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k \longrightarrow 0&amp;lt;/tex&amp;gt;. Докажем по определению.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим некоторое &amp;lt;tex&amp;gt;\varepsilon &amp;gt; 0&amp;lt;/tex&amp;gt;, подбираем &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt;n \ge N \Rightarrow |\alpha_n| &amp;lt; \varepsilon / 2&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k = \frac 1{n + 1} \sum\limits_{k = 0}^N \alpha_k + \sum\limits_{k = N + 1}^n \alpha_k&amp;lt;/tex&amp;gt;&lt;br /&gt;
&amp;lt;tex&amp;gt;\left | \frac 1{2n + 1} \sum\limits_{k = 0}^n \alpha_k \right | \le \frac 1{n + 1} \sum\limits_{k = 0}^N |\alpha_k| + \frac {n - N}{n + 1} \varepsilon&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поскольку в первом слагаемом бесконечно малая умножается на константу, то начиная с &amp;lt;tex&amp;gt;N_1&amp;lt;/tex&amp;gt; выполняется &amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n |\alpha_k| &amp;lt; \varepsilon / 2&amp;lt;/tex&amp;gt;. Но, поскольку &amp;lt;tex&amp;gt;\frac {n - N}{n + 1} &amp;lt; 1&amp;lt;/tex&amp;gt;, то, начиная с &amp;lt;tex&amp;gt;N + N_1&amp;lt;/tex&amp;gt; выполняется &amp;lt;tex&amp;gt;\left | \frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k \right | &amp;lt; \varepsilon&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно, по определению предела &amp;lt;tex&amp;gt;\frac 1{n + 1} \sum\limits_{k = 0}^n \alpha_k&amp;lt;/tex&amp;gt; стремится к нулю.&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=7691</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=7691"/>
				<updated>2011-02-16T18:32:10Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Добро пожаловать на сайт вики-конспектов!&lt;br /&gt;
&lt;br /&gt;
[[Дискретная математика и алгоритмы|Дискретная математика и алгоритмы - 1, 2 семестр]]&lt;br /&gt;
&lt;br /&gt;
[[Математический анализ 1 курс | Математический анализ - 1, 2 семестр]]&lt;br /&gt;
&lt;br /&gt;
[[Алгоритмы и структуры данных|Алгоритмы и структуры данных - 3, 4 семестр]]&lt;br /&gt;
&lt;br /&gt;
[[Алгоритмы алгебры и теории чисел|Алгоритмы алгебры и теории чисел - 4 семестр]]&lt;br /&gt;
&lt;br /&gt;
[[Теория формальных языков|Теория формальных языков - 5 семестр]]&lt;br /&gt;
&lt;br /&gt;
[[Теория сложности|Теория сложности - 6 семестр]]&lt;br /&gt;
&lt;br /&gt;
[[Функциональный анализ|Функциональный анализ - 5, 6 семестр]]&lt;br /&gt;
&lt;br /&gt;
[[Параллельное программирование - 6 семестр]]&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D0%BD%D0%B0%D0%B8%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5%D0%B9_%D0%BE%D0%B1%D1%89%D0%B5%D0%B9_%D0%BF%D0%BE%D0%B4%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8&amp;diff=5453</id>
		<title>Задача о наибольшей общей подпоследовательности</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D0%BD%D0%B0%D0%B8%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5%D0%B9_%D0%BE%D0%B1%D1%89%D0%B5%D0%B9_%D0%BF%D0%BE%D0%B4%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8&amp;diff=5453"/>
				<updated>2010-12-02T22:56:41Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Задача нахождения '''наибольшей общей подпоследовательности''' (''англ.'' '''''longest common subsequence, LCS''''') — это задача поиска последовательности, которая является подпоследовательностью нескольких последовательностей (обычно двух).&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
&lt;br /&gt;
Подпоследовательность можно получить из некоторой конечной последовательности, если удалить из последней некоторое множество её элементов (возможно пустое). Например, BCDB является подпоследовательностью последовательности ABCDBAB. Будем говорить, что последовательность Z является общей подпоследовательностью последовательностей X и Y, если Z является подпоследовательностью как X, так и Y. Требуется для двух последовательностей X и Y найти общую подпоследовательность наибольшей длины. Заметим, что НОП может быть несколько.&lt;br /&gt;
&lt;br /&gt;
== Наивная идея решения ==&lt;br /&gt;
&lt;br /&gt;
Переберем все различные подпоследовательности обеих строк и сравним их. Мы гарантированно найдем искомую НОП, однако время работы алгоритма будет экспоненциально зависеть от длины исходных последовательностей.&lt;br /&gt;
&lt;br /&gt;
== Динамическое программирование ==&lt;br /&gt;
=== Решение ===&lt;br /&gt;
Обозначим как &amp;lt;math&amp;gt;a_{i, j}&amp;lt;/math&amp;gt; НОП префиксов данных последовательностей, заканчивающихся в элементах с номерами &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; соответственно.Получаем следующее рекуррентное соотношение:&lt;br /&gt;
*&amp;lt;math&amp;gt;a_{i, j} = a_{i - 1, j - 1} + 1&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;s[i] = s[j]&amp;lt;/math&amp;gt; (соответствующие элементы последовательностей равны)&lt;br /&gt;
*&amp;lt;math&amp;gt;a_{i, j} = max(a_{i, j - 1}, a_{i - 1, j})&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;s1[i] &amp;lt;&amp;gt; s2[j]&amp;lt;/math&amp;gt; (соответствующие элементы последовательностей не равны).&lt;br /&gt;
Очевидно, что сложность алгоритма составит &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Доказательство оптимальности ===&lt;br /&gt;
Предположим, что некоторое значение &amp;lt;math&amp;gt;a_{i, j}&amp;lt;/math&amp;gt; посчитано неверно. Однако, в случае различия соответствующих символов, они не могут одновременно участвовать в НОП, а значит ответ действительно равен формуле для случая с различными символами. В случае же равенства, ответ не может быть больше, чем &amp;lt;math&amp;gt;a_{i - 1, j - 1} + 1&amp;lt;/math&amp;gt;, так как тогда неверно посчитано значение &amp;lt;math&amp;gt;a_{i - 1, j - 1} + 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение подпоследовательности ===&lt;br /&gt;
Для каждой пары элементов будем хранить не только длину НОП соответствующих префиксов, но и номера последних элементов, участвующих в этой НОП.Таким образом, посчитав ответ, мы сможем восстановить всю наибольшую общую подпоследовательность.&lt;br /&gt;
&lt;br /&gt;
=== Пример реализации на Java ===&lt;br /&gt;
  public int[] lcs(int[] s1, int[] s2) {&lt;br /&gt;
      int[][] a = new int[s1.length][s2.length];&lt;br /&gt;
      int[][] last_1 = new int[s1.length][s2.length];&lt;br /&gt;
      int[][] last_2 = new int[s1.length][s2.length];&lt;br /&gt;
      //Подсчет значений&lt;br /&gt;
      for (int i = 0; i &amp;lt; s1.length; i++)&lt;br /&gt;
          for (int j = 0; j &amp;lt; s2.length; j++) {&lt;br /&gt;
              if (s1[i] == s2[j])&lt;br /&gt;
                  if ((i == 0) || (j == 0)) {&lt;br /&gt;
                      a[i][j] = 1;&lt;br /&gt;
                      last_1[i][j] = i;&lt;br /&gt;
                      last_2[i][j] = j;&lt;br /&gt;
                  } else {&lt;br /&gt;
                      a[i][j] = a[i - 1][j - 1] + 1;&lt;br /&gt;
                      last_1[i][j] = i;&lt;br /&gt;
                      last_2[i][j] = j;&lt;br /&gt;
                  }&lt;br /&gt;
              else {&lt;br /&gt;
                  if ((i &amp;gt; 0) &amp;amp;&amp;amp; (a[i - 1][j] &amp;gt; a[i][j])) {&lt;br /&gt;
                      a[i][j] = a[i - 1][j];&lt;br /&gt;
                      last_1[i][j] = last_1[i - 1][j];&lt;br /&gt;
                      last_2[i][j] = last_2[i - 1][j];&lt;br /&gt;
                  }&lt;br /&gt;
                  if ((j &amp;gt; 0) &amp;amp;&amp;amp; (a[i][j - 1] &amp;gt; a[i][j])) {&lt;br /&gt;
                      a[i][j] = a[i][j - 1];&lt;br /&gt;
                      last_1[i][j] = last_1[i][j - 1];&lt;br /&gt;
                      last_2[i][j] = last_2[i][j - 1];&lt;br /&gt;
                  }&lt;br /&gt;
              }&lt;br /&gt;
          }&lt;br /&gt;
         &lt;br /&gt;
        //Восстановление последовательности&lt;br /&gt;
        int l = a[s1.length - 1][s2.length - 1];&lt;br /&gt;
        int[] ans = new int[l];&lt;br /&gt;
        int ti = s1.length - 1;&lt;br /&gt;
        int tj = s2.length - 1;&lt;br /&gt;
        while (l &amp;gt; 0){&lt;br /&gt;
            ans[l - 1] = s1[last_1[ti][tj]];&lt;br /&gt;
            int nti = last_1[ti][tj] - 1;&lt;br /&gt;
            int ntj = last_2[ti][tj] - 1;&lt;br /&gt;
            ti = nti;&lt;br /&gt;
            tj = ntj;&lt;br /&gt;
            l--;&lt;br /&gt;
        }&lt;br /&gt;
        return ans;&lt;br /&gt;
    }&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D0%BD%D0%B0%D0%B8%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5%D0%B9_%D0%BE%D0%B1%D1%89%D0%B5%D0%B9_%D0%BF%D0%BE%D0%B4%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8&amp;diff=5452</id>
		<title>Задача о наибольшей общей подпоследовательности</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D0%BD%D0%B0%D0%B8%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5%D0%B9_%D0%BE%D0%B1%D1%89%D0%B5%D0%B9_%D0%BF%D0%BE%D0%B4%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8&amp;diff=5452"/>
				<updated>2010-12-02T22:47:50Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Задача нахождения '''наибольшей общей подпоследовательности''' (''англ.'' '''''longest common subsequence, LCS''''') — это задача поиска последовательности, которая является подпоследовательностью нескольких последовательностей (обычно двух).&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
&lt;br /&gt;
Подпоследовательность можно получить из некоторой конечной последовательности, если удалить из последней некоторое множество её элементов (возможно пустое). Например, BCDB является подпоследовательностью последовательности ABCDBAB. Будем говорить, что последовательность Z является общей подпоследовательностью последовательностей X и Y, если Z является подпоследовательностью как X, так и Y. Требуется для двух последовательностей X и Y найти общую подпоследовательность наибольшей длины. Заметим, что НОП может быть несколько.&lt;br /&gt;
&lt;br /&gt;
== Наивная идея решения ==&lt;br /&gt;
&lt;br /&gt;
Переберем все различные подпоследовательности обеих строк и сравним их. Мы гарантированно найдем искомую НОП, однако время работы алгоритма будет экспоненциально зависеть от длины исходных последовательностей.&lt;br /&gt;
&lt;br /&gt;
== Динамическое программирование ==&lt;br /&gt;
=== Решение ===&lt;br /&gt;
Обозначим как &amp;lt;math&amp;gt;a_{i, j}&amp;lt;/math&amp;gt; НОП префиксов данных последовательностей, заканчивающихся в элементах с номерами &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; соответственно.Получаем следующее рекуррентное соотношение:&lt;br /&gt;
*&amp;lt;math&amp;gt;a_{i, j} = a_{i - 1, j - 1} + 1&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;s[i] = s[j]&amp;lt;/math&amp;gt; (соответствующие элементы последовательностей равны)&lt;br /&gt;
*&amp;lt;math&amp;gt;a_{i, j} = max(a_{i, j - 1}, a_{i - 1, j})&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;s1[i] &amp;lt;&amp;gt; s2[j]&amp;lt;/math&amp;gt; (соответствующие элементы последовательностей не равны).Очевидно, что сложность алгоритма составит &amp;lt;math&amp;gt;O(n^2)&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Доказательство оптимальности ===&lt;br /&gt;
Предположим, что некоторое значение &amp;lt;math&amp;gt;a_{i, j}&amp;lt;/math&amp;gt; посчитано неверно. Однако, в случае различия соответствующих символов, они не могут одновременно участвовать в НОП, а значит ответ действительно равен формуле для случая с различными символами. В случае же равенства, ответ не может быть больше, чем &amp;lt;math&amp;gt;a_{i - 1, j - 1} + 1&amp;lt;/math&amp;gt;, так как тогда неверно посчитано значение &amp;lt;math&amp;gt;a_{i - 1, j - 1} + 1&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Построение подпоследовательности ===&lt;br /&gt;
Для каждой пары элементов будем хранить не только длину НОП соответствующих префиксов, но и номера последних элементов, участвующих в этой НОП.Таким образом, посчитав ответ, мы сможем восстановить всю наибольшую общую подпоследовательность.&lt;br /&gt;
&lt;br /&gt;
=== Пример реализации на Java ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font size = 3&amp;gt;&lt;br /&gt;
      public int[] lcs(int[] s1, int[] s2) {&lt;br /&gt;
          int[][] a = new int[s1.length][s2.length];&lt;br /&gt;
          int[][] last_1 = new int[s1.length][s2.length];&lt;br /&gt;
          int[][] last_2 = new int[s1.length][s2.length];&lt;br /&gt;
          //Подсчет значений&lt;br /&gt;
          for (int i = 0; i &amp;lt; s1.length; i++)&lt;br /&gt;
              for (int j = 0; j &amp;lt; s2.length; j++) {&lt;br /&gt;
                  if (s1[i] == s2[j])&lt;br /&gt;
                      if ((i == 0) || (j == 0)) {&lt;br /&gt;
                          a[i][j] = 1;&lt;br /&gt;
                          last_1[i][j] = i;&lt;br /&gt;
                          last_2[i][j] = j;&lt;br /&gt;
                      } else {&lt;br /&gt;
                          a[i][j] = a[i - 1][j - 1] + 1;&lt;br /&gt;
                          last_1[i][j] = i;&lt;br /&gt;
                          last_2[i][j] = j;&lt;br /&gt;
                      }&lt;br /&gt;
                  else {&lt;br /&gt;
                      if ((i &amp;gt; 0) &amp;amp;&amp;amp; (a[i - 1][j] &amp;gt; a[i][j])) {&lt;br /&gt;
                          a[i][j] = a[i - 1][j];&lt;br /&gt;
                          last_1[i][j] = last_1[i - 1][j];&lt;br /&gt;
                          last_2[i][j] = last_2[i - 1][j];&lt;br /&gt;
                      }&lt;br /&gt;
                      if ((j &amp;gt; 0) &amp;amp;&amp;amp; (a[i][j - 1] &amp;gt; a[i][j])) {&lt;br /&gt;
                          a[i][j] = a[i][j - 1];&lt;br /&gt;
                          last_1[i][j] = last_1[i][j - 1];&lt;br /&gt;
                          last_2[i][j] = last_2[i][j - 1];&lt;br /&gt;
                      }&lt;br /&gt;
                  }&lt;br /&gt;
              }&lt;br /&gt;
              &lt;br /&gt;
          //Восстановление последовательности&lt;br /&gt;
          int l = a[s1.length - 1][s2.length - 1];&lt;br /&gt;
          int[] ans = new int[l];&lt;br /&gt;
          int ti = s1.length - 1;&lt;br /&gt;
          int tj = s2.length - 1;&lt;br /&gt;
          while (l &amp;gt; 0){&lt;br /&gt;
              ans[l - 1] = s1[last_1[ti][tj]];&lt;br /&gt;
              int nti = last_1[ti][tj] - 1;&lt;br /&gt;
              int ntj = last_2[ti][tj] - 1;&lt;br /&gt;
              ti = nti;&lt;br /&gt;
              tj = ntj;&lt;br /&gt;
              l--;&lt;br /&gt;
          }&lt;br /&gt;
          return ans;&lt;br /&gt;
      }&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D0%BD%D0%B0%D0%B8%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5%D0%B9_%D0%BE%D0%B1%D1%89%D0%B5%D0%B9_%D0%BF%D0%BE%D0%B4%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8&amp;diff=5450</id>
		<title>Задача о наибольшей общей подпоследовательности</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%97%D0%B0%D0%B4%D0%B0%D1%87%D0%B0_%D0%BE_%D0%BD%D0%B0%D0%B8%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%B5%D0%B9_%D0%BE%D0%B1%D1%89%D0%B5%D0%B9_%D0%BF%D0%BE%D0%B4%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8&amp;diff=5450"/>
				<updated>2010-12-02T19:27:43Z</updated>
		
		<summary type="html">&lt;p&gt;Pashkal: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Задача нахождения '''наибольшей общей подпоследовательности''' (''англ.'' '''''longest common subsequence, LCS''''') — это задача поиска последовательности, которая является подпоследовательностью нескольких последовательностей (обычно двух).&lt;br /&gt;
&lt;br /&gt;
== Постановка задачи ==&lt;br /&gt;
&lt;br /&gt;
Подпоследовательность можно получить из некоторой конечной последовательности, если удалить из последней некоторое множество её элементов (возможно пустое). Например, BCDB является подпоследовательностью последовательности ABCDBAB. Будем говорить, что последовательность Z является общей подпоследовательностью последовательностей X и Y, если Z является подпоследовательностью как X, так и Y. Требуется для двух последовательностей X и Y найти общую подпоследовательность наибольшей длины. Заметим, что НОП может быть несколько.&lt;br /&gt;
&lt;br /&gt;
== Наивная идея решения ==&lt;br /&gt;
&lt;br /&gt;
Переберем все различные подпоследовательности обеих строк и сравним их. Мы гарантированно найдем искомую НОП, однако время работы алгоритма будет экспоненциально зависеть от длины исходных последовательностей.&lt;br /&gt;
&lt;br /&gt;
== Динамическое программирование ==&lt;br /&gt;
=== Решение ===&lt;br /&gt;
Обозначим как &amp;lt;math&amp;gt;a_{i, j}&amp;lt;/math&amp;gt; НОП префиксов данных последовательностей длины &amp;lt;math&amp;gt;i&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;j&amp;lt;/math&amp;gt; соответственно.Получаем следующее рекуррентное соотношение:&lt;br /&gt;
*&amp;lt;math&amp;gt;a_{i, j} = a_{i - 1, j - 1} + 1&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;s[i] = s[j]&amp;lt;/math&amp;gt; (соответствующие элементы последовательностей равны)&lt;br /&gt;
*&amp;lt;math&amp;gt;a_{i, j} = max(a_{i, j - 1}, a_{i - 1, j})&amp;lt;/math&amp;gt;, если &amp;lt;math&amp;gt;s[i] &amp;lt;&amp;gt; s[j]&amp;lt;/math&amp;gt; (соответствующие элементы последовательностей не равны)&lt;br /&gt;
&lt;br /&gt;
=== Доказательство оптимальности ===&lt;br /&gt;
Предположим, что некоторое значение &amp;lt;math&amp;gt;a_{i, j}&amp;lt;/math&amp;gt; посчитано неверно. Однако, в случае равенства соответствующих символов, &lt;br /&gt;
&lt;br /&gt;
== Итого ==&lt;br /&gt;
&lt;br /&gt;
== Спасибо за внимание==&lt;/div&gt;</summary>
		<author><name>Pashkal</name></author>	</entry>

	</feed>