Так как все элементы в дереве поиска упорядочены по ключу, будем считать, что у нас есть ключ -- индекс элемента, постепенно увеличивающийся на 1 слева направо -- и вместо номера будем хранить количество элементов в поддереве. Тогда декартово дерево превращается в структуру данных, поддерживающую операции АТД Массив и АТД Список за `O(log N)`.
Основные операции:
Операция|Эффективность|Вызов
--|--|--
создать пустой набор ||`O(1)`|| ``ITreap<int> t;``
количество элементов |`O(1)`| ``size_t kol=t.size();``
получить/изменить i-й |`O(log N)`| ``auto v=t[i]; t[i]=4;``
удалить i-й |`O(log N)`| ``t.erasei(i);``
вставить значение v перед i-м |`O(log N)`| ``it.inserti(i,v);``
внутренний итератор |`O(n)`| ``t.foreach([&](int& v) { cout<<v<<"\n";});``
--
```
template <typename T>
class ITreap {
struct node {
T v; // значение элемента
size_t k; // неявный ключ - количество элементов в поддереве
int y; // случайная высота
node *left=nullptr, *right=nullptr;
node(T v) : v(v), k(1), y(rand()) { }
void update() { k=1+size(left)+size(right); }
};
node *root;
static size_t size(node *n) { return n?n->k:0; }
public:
ITreap():root(nullptr) {}
ITreap(const ITreap&)=delete; // запрет копирования
ITreap& operator=(const ITreap&)=delete; // запрет присваивания
~ITreap() { free(root); }
size_t size() const { return size(root); } // размер
...
};
```
--
Операции разрезания и слияния останутся почти такими же, но добавится вызов update для пересчета количества элементов в поддереве: