<?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=188.130.155.154&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=188.130.155.154&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/188.130.155.154"/>
		<updated>2026-08-05T16:35:01Z</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=60455</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=60455"/>
				<updated>2017-02-23T05:59:49Z</updated>
		
		<summary type="html">&lt;p&gt;188.130.155.154: /* Split */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Основная идея==&lt;br /&gt;
Возьмем структуру данных [[Саморасширяющийся массив|динамический массив]]. В её стандартной реализации мы умеем добавлять элемент в конец вектора, узнавать значение элемента, стоящего на определенной позиции, изменять элемент по номеру и удалять последний элемент. Предположим, что нам необходима структура данных с вышеуказанными свойствами, а также с операциями: добавить элемент в любое место (с соответствующим изменением нумерации элементов) и удалить любой элемент (также с соответствующим изменением нумерации). Такую структуру можно реализовать на базе декартового дерева, результат часто называют '''декартово дерево по неявному ключу''' (англ. ''Treap with implicit key'').&lt;br /&gt;
===Ключ X===&lt;br /&gt;
Как известно, [[декартово дерево]] {{---}} это структура данных, объединяющая в себе [[Дерево_поиска,_наивная_реализация|бинарное дерево поиска]] и [[Двоичная_куча|бинарную кучу]]. При реализации же декартова дерева по неявному ключу модифицируем эту структуру. А именно, оставим в нем только приоритет &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, а вместо ключа &amp;lt;tex&amp;gt;X&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;
===Вспомогательная величина С===&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;
[[Файл:DDpoNK.png|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: &amp;lt;tex&amp;gt;\mathrm{split}&amp;lt;/tex&amp;gt;  {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt; {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: &amp;lt;tex&amp;gt;\mathrm{split(root, t)}&amp;lt;/tex&amp;gt; {{---}} разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и &amp;lt;tex&amp;gt;\mathrm{merge(root1, root)}&amp;lt;/tex&amp;gt; {{---}} слияние двух любых деревьев, соответственно.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура &amp;lt;tex&amp;gt;\mathrm{split}&amp;lt;/tex&amp;gt; запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;k&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;. Рассмотрим все возможные случаи: &lt;br /&gt;
* &amp;lt;tex&amp;gt;l \geqslant k&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру &amp;lt;tex&amp;gt;\mathrm{split}&amp;lt;/tex&amp;gt; от левого сына с тем же параметром &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. При этом новым левым сыном корня станет правая часть ответа рекурсивной процедуры, а правой частью ответа станет корень.&lt;br /&gt;
* &amp;lt;tex&amp;gt;l &amp;lt; k&amp;lt;/tex&amp;gt; Случай симметричен предыдущему. Рекурсивно запустим процедуру &amp;lt;tex&amp;gt;\mathrm{split}&amp;lt;/tex&amp;gt;  от правого сына с параметром &amp;lt;tex&amp;gt;k - l - 1&amp;lt;/tex&amp;gt;. При этом новым правым сыном корня станет левая часть ответа рекурсивной процедуры, а левой частью ответа станет корень.&lt;br /&gt;
&lt;br /&gt;
Псевдокод:&lt;br /&gt;
&lt;br /&gt;
 '''&amp;lt;Treap, Treap&amp;gt;''' split('''Treap''' t, '''int''' k)&lt;br /&gt;
   '''int''' l = t.left.size&lt;br /&gt;
   '''if''' l &amp;gt;= k&lt;br /&gt;
     &amp;lt;t1, t2&amp;gt; = split(t.left, k)&lt;br /&gt;
     t.left = t2&lt;br /&gt;
     update(t)&lt;br /&gt;
     '''return''' &amp;lt;t1, t&amp;gt;&lt;br /&gt;
   '''else'''&lt;br /&gt;
     &amp;lt;t1, t2&amp;gt; = split(t.right, k - l - 1)&lt;br /&gt;
     t.right = t1&lt;br /&gt;
     update(t)&lt;br /&gt;
     '''return''' &amp;lt;t, t2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из [[Декартово дерево#Операция merge|реализаций]] процедуры &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt;. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt; для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности значений C===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих значений заключается в том, что после любого действия с детьми вершины нужно записать в ее поле &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; сумму этих значений в ее новых детях, увеличенную на единицу.&lt;br /&gt;
&lt;br /&gt;
Псевдокод:&lt;br /&gt;
 '''void''' update('''Treap''' t)&lt;br /&gt;
   t.size = 1 + t.left.size + t.right.size&lt;br /&gt;
&lt;br /&gt;
==Применение описанного дерева==&lt;br /&gt;
Таким образом, описана структура, от которой можно отрезать слева часть произвольной длины и слить две любые части в одну в нужном порядке. Теперь мы имеем возможность:&lt;br /&gt;
* вставить элемент в любое место (отрежем нужное количество элементов слева, сольем левое дерево с деревом из одного добавленного элемента и результат {{---}} с правым деревом),&lt;br /&gt;
* переставить любой кусок массива куда угодно (сделаем нужные разрезы и слияния в правильном порядке),&lt;br /&gt;
* совершать групповые операции с элементами. Вспомним реализацию таких операций в дереве отрезков и поймем, что ничего не помешает нам сделать то же самое с описанным деревом. В групповые операции включается, естественно, и взятие функции от отрезка,&lt;br /&gt;
* сделав на одном исходном массиве два дерева из элементов разной четности, можно решить задачу про смену мест четных и нечетных на отрезке,&lt;br /&gt;
* используя идеи декартова дерева по неявному ключу, можно реализовать такую структуру данных как [[Rope|Rope]].&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [http://habrahabr.ru/post/102364/ Habrahabr {{---}} Декартово дерево по неявному ключу]&lt;br /&gt;
* [http://e-maxx.ru/algo/treap#7 MAXimal :: algo :: Неявные декартовы деревья]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Деревья поиска]]&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Структуры данных]]&lt;/div&gt;</summary>
		<author><name>188.130.155.154</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=60454</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=60454"/>
				<updated>2017-02-23T05:52:06Z</updated>
		
		<summary type="html">&lt;p&gt;188.130.155.154: /* Split */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Основная идея==&lt;br /&gt;
Возьмем структуру данных [[Саморасширяющийся массив|динамический массив]]. В её стандартной реализации мы умеем добавлять элемент в конец вектора, узнавать значение элемента, стоящего на определенной позиции, изменять элемент по номеру и удалять последний элемент. Предположим, что нам необходима структура данных с вышеуказанными свойствами, а также с операциями: добавить элемент в любое место (с соответствующим изменением нумерации элементов) и удалить любой элемент (также с соответствующим изменением нумерации). Такую структуру можно реализовать на базе декартового дерева, результат часто называют '''декартово дерево по неявному ключу''' (англ. ''Treap with implicit key'').&lt;br /&gt;
===Ключ X===&lt;br /&gt;
Как известно, [[декартово дерево]] {{---}} это структура данных, объединяющая в себе [[Дерево_поиска,_наивная_реализация|бинарное дерево поиска]] и [[Двоичная_куча|бинарную кучу]]. При реализации же декартова дерева по неявному ключу модифицируем эту структуру. А именно, оставим в нем только приоритет &amp;lt;tex&amp;gt;Y&amp;lt;/tex&amp;gt;, а вместо ключа &amp;lt;tex&amp;gt;X&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;
===Вспомогательная величина С===&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;
[[Файл:DDpoNK.png|Пример описанного дерева с демонстрацией определения ключа &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
==Операции, поддерживающие структуру декартова дерева==&lt;br /&gt;
Структура обычного декартова дерева поддерживается с помощью двух операций: &amp;lt;tex&amp;gt;\mathrm{split}&amp;lt;/tex&amp;gt;  {{---}} разбиение одного декартова дерева  на два таких, что в одном ключ &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем заданное значение, а в другом {{---}} больше, и &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt; {{---}} слияние двух деревьев, в одном из которых все ключи &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; меньше, чем во втором. С учетом отличий декартова дерева по неявному ключу от обычного, операции теперь будут описываться так: &amp;lt;tex&amp;gt;\mathrm{split(root, t)}&amp;lt;/tex&amp;gt; {{---}} разбиение дерева на два так, что в левом окажется ровно &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; вершин, и &amp;lt;tex&amp;gt;\mathrm{merge(root1, root)}&amp;lt;/tex&amp;gt; {{---}} слияние двух любых деревьев, соответственно.&lt;br /&gt;
&lt;br /&gt;
===Split===&lt;br /&gt;
Пусть процедура &amp;lt;tex&amp;gt;\mathrm{split}&amp;lt;/tex&amp;gt; запущена в корне дерева с требованием отрезать от дерева &amp;lt;tex&amp;gt;k&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;. Рассмотрим все возможные случаи: &lt;br /&gt;
* &amp;lt;tex&amp;gt;l \geqslant k&amp;lt;/tex&amp;gt;. В этом случае нужно рекурсивно запустить процедуру &amp;lt;tex&amp;gt;\mathrm{split}&amp;lt;/tex&amp;gt; от левого сына с тем же параметром &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. При этом новым левым сыном корня станет правая часть ответа рекурсивной процедуры, а правой частью ответа станет корень.&lt;br /&gt;
* &amp;lt;tex&amp;gt;l &amp;lt; k&amp;lt;/tex&amp;gt; Случай симметричен предыдущему. Рекурсивно запустим процедуру &amp;lt;tex&amp;gt;\mathrm{split}&amp;lt;/tex&amp;gt;  от правого сына с параметром &amp;lt;tex&amp;gt;k - l - 1&amp;lt;/tex&amp;gt;. При этом новым правым сыном корня станет левая часть ответа рекурсивной процедуры, а левой частью ответа станет корень.&lt;br /&gt;
&lt;br /&gt;
Псевдокод:&lt;br /&gt;
&lt;br /&gt;
 '''&amp;lt;Treap, Treap&amp;gt;''' split('''Treap''' t, '''int''' k)&lt;br /&gt;
   '''int''' l = t.left.size&lt;br /&gt;
   '''if''' l &amp;gt;= k&lt;br /&gt;
     &amp;lt;t1, t2&amp;gt; = split(t.left, k)&lt;br /&gt;
     t.left = t2&lt;br /&gt;
     update(v)&lt;br /&gt;
     r = v&lt;br /&gt;
     '''return''' &amp;lt;t1, t&amp;gt;&lt;br /&gt;
   '''else'''&lt;br /&gt;
     &amp;lt;t1, t2&amp;gt; = split(t.right, k - l - 1)&lt;br /&gt;
     t.right = t1&lt;br /&gt;
     update(v)&lt;br /&gt;
     l = v&lt;br /&gt;
     '''return''' &amp;lt;t, t2&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Merge===&lt;br /&gt;
Посмотрим любую из [[Декартово дерево#Операция merge|реализаций]] процедуры &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt;. Заметим, что в ней программа ни разу не обращается к ключу &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt;. Поэтому реализация процедуры &amp;lt;tex&amp;gt;\mathrm{merge}&amp;lt;/tex&amp;gt; для декартова дерева по неявному ключу вообще не будет отличаться от реализации той же процедуры в обычном декартовом дереве.&lt;br /&gt;
&lt;br /&gt;
===Поддержание корректности значений C===&lt;br /&gt;
Единственное действие, обеспечивающее корректность этих значений заключается в том, что после любого действия с детьми вершины нужно записать в ее поле &amp;lt;tex&amp;gt;C&amp;lt;/tex&amp;gt; сумму этих значений в ее новых детях, увеличенную на единицу.&lt;br /&gt;
&lt;br /&gt;
Псевдокод:&lt;br /&gt;
 '''void''' update('''Treap''' t)&lt;br /&gt;
   t.size = 1 + t.left.size + t.right.size&lt;br /&gt;
&lt;br /&gt;
==Применение описанного дерева==&lt;br /&gt;
Таким образом, описана структура, от которой можно отрезать слева часть произвольной длины и слить две любые части в одну в нужном порядке. Теперь мы имеем возможность:&lt;br /&gt;
* вставить элемент в любое место (отрежем нужное количество элементов слева, сольем левое дерево с деревом из одного добавленного элемента и результат {{---}} с правым деревом),&lt;br /&gt;
* переставить любой кусок массива куда угодно (сделаем нужные разрезы и слияния в правильном порядке),&lt;br /&gt;
* совершать групповые операции с элементами. Вспомним реализацию таких операций в дереве отрезков и поймем, что ничего не помешает нам сделать то же самое с описанным деревом. В групповые операции включается, естественно, и взятие функции от отрезка,&lt;br /&gt;
* сделав на одном исходном массиве два дерева из элементов разной четности, можно решить задачу про смену мест четных и нечетных на отрезке,&lt;br /&gt;
* используя идеи декартова дерева по неявному ключу, можно реализовать такую структуру данных как [[Rope|Rope]].&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Splay-дерево]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [http://habrahabr.ru/post/102364/ Habrahabr {{---}} Декартово дерево по неявному ключу]&lt;br /&gt;
* [http://e-maxx.ru/algo/treap#7 MAXimal :: algo :: Неявные декартовы деревья]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Деревья поиска]]&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Структуры данных]]&lt;/div&gt;</summary>
		<author><name>188.130.155.154</name></author>	</entry>

	</feed>