真·无旋Treap模板
为了方便地重用代码,C++有了模板和多态功能。
然而OIer一般并不会花时间写这些
(除了我这种实际上已经AFO的人
这个板子喜欢的可以拿去用…出锅了概不负责私信我改awa
码风最早是学习了P3369题解中的红黑树代码,后来参考了GNU STL
和自己的偏好,基本固定了写大模板的风格。
再简单讲一讲Treap的思想
Treap是一种基于随机化的自平衡二叉搜索树。为了避免二叉搜索树在精心构造的数据下退化,Treap给每个结点增加了一个随机权值,并设法使随机权值满足堆的性质。将命运掌握在了自己手中
常见的Treap通过插入、删除结点后进行旋转来维持其性质。然而由于Treap的性质简单而容易维护,Treap可以容易地在 O ( l o g 2 n ) O(log_2 n) O(log2n)的时间内分裂成两棵值域不相交的Treap,两棵不相交的Treap也可以在相同时间内合并。
于是国内一位叫做fhq的神仙据此给出了Treap依赖于分裂、合并的一种实现,以牺牲一定运行效率的代价,换取了相对简洁的代码和更加灵活的功能,使得Treap可以维护区间信息。
然而Treap怎么打并不是重点,模板才是。
为了能够在日后日常做题中避免反复打模板,干脆花了一上午敲了一个封装好的板子,也算是锻炼码力。
并且这也是我第一次完全用自己的代码写完普通平衡树
功能和std::set
基本相同,实现了一个不可重集合,支持set
支持的各类查找操作并支持了查询元素排名和按排名查询(当然效率比起红黑树低一些
一些细小的函数懒得实现,分配器、萃取器啥的麻烦又难搞也没写。尾后迭代器…由于个人能力不足,不得不采用一种丑陋的实现方式,导致空间占用变大…凑合着用吧
代码(底下有说明,代码可以先略过不看)
怎么比我封装好的LCT还长不少
#ifndef TREAP_TEMPLATE //Treap template
#define TREAP_TEMPLATE
#if __cplusplus>=201103L
#include<random>
#endif
#if __cplusplus<201103L
#ifdef nullptr
#undef nullptr
#endif
#define nullptr NULL
#endif
template<typename _Tp,typename _Cmp=std::less<_Tp>,typename _Alloc=std::allocator<_Tp> >
class treap:_Cmp
{
public:
typedef _Tp Value_type;
typedef _Cmp Comparator_type;
typedef size_t size_type;
typedef _Alloc alloc_type;
#if __cplusplus>=201103L
typedef typename std::allocator_traits<_Alloc> alloc_traits_type;
#endif
private:
struct Node;
Node *end_node;
Node *&root;
inline Node *__get_new_node(_Tp);
inline void __emplace_node(Node*,_Tp);
inline void __delete_node(Node*);
Node *merge(Node*,Node*);
void split_val(Node*,const _Tp&,Node*&,Node*&);
void split_val_equal(Node*,const _Tp&,Node*&,Node*&);
inline static unsigned long long get_pri();
void destroy_inner_nodes(Node*);
typedef typename _Alloc::template rebind<Node>::other _node_alloc_type;
#if __cplusplus>=201103L
typedef typename alloc_traits_type::template rebind_traits<Node> _node_alloc_traits_type;
#endif
_node_alloc_type _node_allocator;
public:
struct iterator;
treap():
end_node(new Node),
root(end_node->lc)
{
}
~treap();
std::pair<iterator,bool> insert(const _Tp&);
bool erase(const _Tp&);
iterator begin()const;
iterator end()const;
iterator find(const _Tp&)const;
iterator lower_bound(const _Tp&)const;
iterator upper_bound(const _Tp&)const;
iterator find_by_order(const size_type&)const;
size_type order_of_key(const _Tp&)const;
size_type size()const;
};
template<typename _Tp,typename _Cmp,typename _Alloc>
struct treap<_Tp,_Cmp,_Alloc>::Node
{
_Tp value;
unsigned long long pri;
size_type s;
Node *lc,*rc,*ftr;
Node():
pri(get_pri()),
s(1),
lc(nullptr),
rc(nullptr),
ftr(nullptr)
{
}
Node(_Tp val):
value(val),
pri(rand()),
s(1),
lc(nullptr),
rc(nullptr),
ftr(nullptr)
{
}
void maintain(