Как стать автором
Обновить

Комментарии 27

Дирамида и правда напрашивается стать персистентной, алгоритм тоже неплохой, но…

Конструктор копирования, принимающий указатель? Отсутствие деструктора?! link = 0 в конструкторе копирования? Ручной подсчет ссылок?! Да, это и правда ненормальное программирование…
Первоначально данная структура использовалась только на олимпиаде. Поэтому удаление вершины возможно только после вызова метода del для нее, он работает вместо деструктора, точнее только в нем адекватно удаление объекта, что вполне оправдано, на мой взгляд.
Аналогично с ссылками. Да, link = 0, ведь это копия, а не исходная вершина.
С ручным подсчетом согласен, накосячил… Можете подсказать более адекватный вариант?
Вариант 1. typedef std::shared_ptr<PersistentTreap> PtrPersistentTreap

Вариант 2 (исключительно для однопоточного доступа)
class PtrPersistentTreap {
    PersistentTreap* ptr;

    void assign(PersistentTreap* newPtr) {
        PersistentTreap* oldPtr = ptr;
        ptr = newPtr;
        if (newPtr) newPtr->link++;
        if (oldPtr && --oldPtr->link == 0) delete oldPtr;
    }
public:
    explicit PtrPersistentTreap(PersistentTreap* ptr = 0) :ptr(0) { assign(ptr); }
    PtrPersistentTreap(PtrPersistentTreap const& other) : ptr(0) { assign(other.ptr); }
    PtrPersistentTreap(PtrPersistentTreap && other) : ptr(other.ptr) { other.ptr = 0; }
    ~PtrPersistentTreap() { assign(0); }

    PtrPersistentTreap& operator = (PersistentTreap* ptr) { assign(ptr); return *this; }
    PtrPersistentTreap& operator = (PtrPersistentTreap const& other) { assign(other.ptr); return *this; }
    PtrPersistentTreap& operator = (PtrPersistentTreap && other) { std::swap(ptr, other.ptr); return *this; }

    PersistentTreap& operator * () const { return *ptr; }
    PersistentTreap* operator -> () const { return ptr; }
};
Вроде ничего не забыл…

Разумеется, в обоих случаях поля left и right должны именно PtrPersistentTreap. Их инициализацию из конструкторов теперь можно и убрать. Функция addLink больше не нужна, как и метод del.

PS да, по поводу link вы правы — там и правда в копии должен стоять ноль. Кстати, хитрая получилась ловушка для любителей умных указателей-велосипедов…
Большое спасибо.
Замечательное объяснение, большое спасибо
Не хватает в начале краткого отступления: что такое декартовое дерево и неявный ключ.
Ну и название — «дерамида».
Первый раз вижу такой перевод английского treap.
Ну, «дерамида» все-таки звучит лучше, нежели «дуча» или «курево». А других вариантов вроде как и нет…
«Курево» тоже впервые вижу.
То есть вы только «дучу» и видели? )
Да.
НЛО прилетело и опубликовало эту надпись здесь
Декартово дерево + пирамида
пирамида = куча
интересная реализация, но зачем в примере персистентность?
Поясню вопрос: В примере по ссылке, добавление, удаление вершин реализовано подменой корня, то есть предыдущие копии как таковые не используются и не нужны. Придумать, когда они могут быть нужны мне с ходу не получилось, может быть кто-нибудь может натолкнуть на пример.

Надеялся увидеть, как персистентная дерамида инкапсулирует работу в многопоточной среде, но получается, что необходимо лочить всю дерамиду ради мерджа (ждать нового корня) даже для добавления одного элемента.
Split и Merge возвращают указатели на корни деревьев, что позволяет их куда-нибудь сохранить. А одновременная работа с декартовым деревом едва ли будет когда-нибудь возможна
Полностью с этим согласен, поэтому и вопрос примера исользования персистентности возник.
Упс, выше я сказал хрень.
Само дерево потому и называется персистентным, что не изменяется, а лишь дополняется при выполнении любых операций, в том числе mergе и split. Соответственно, merge и split можно запускать параллельно, а все остальное лишь базируется на них.
В моем олимпиадном прошлом была задача на персистентное декартово дерево, к сожалению, не могу уже вспомнить
Зачем часть ссылок на промежуточный мердж и часть ссылок на промежуточный split при параллелной работе?
Ну, персистентность изначально делалась не для того, чтобы поддерживать параллельную работу, так что вполне может быть избыточной.
PS: Задача на персистентное декартово дерево: codeforces.ru/contest/292/problem/E
Хм, а зачем тут декартово дерево, да еще и персистентное? Достаточно же дерева интервалов.
Хм, а как?
Обновление сверху. Для каждого интервала хранится либо начальный индекс в массиве a, откуда его заполняли, либо признак того, что ожидающих операций копирования нет. Дальше очевидно.
И правда. Надо восстанавливать квалификацию олимпиадника =(
Чтобы потом сделать операцию CAS. Правда, задача корректного чтения указателя на объект с одновременным увеличением счетчика ссылок на него же намного сложнее, чем реализация персистентного дерева.
Есть вариант задачи именно на персистентную дерамиду. Но чисто в качестве тренировки на ее написании. В виде нормальной олимпиадной задачи найти сложно. Взято из параллели А ЛКШ этого года. (Задача А)
ejudge.lksh.ru/archive/2014/08/A/statements/A-day02.pdf
Так же есть задача со ВКОШПа 2010-го года, которая решается персистентным деревом отрезков, но так же может быть решена при помощи персистентной дерамиды.
codeforces.ru/gym/100043/attachments
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации