赞~美~封~装~

Akano 发布于 2023-10-12 3 次阅读


前言

最近精神状态不是很好,突然想发会儿电了。本文大概就是这种性质的博客。也许,有那么一点点的实际意义吧。

为什么封装是神?

给他一个可持久化线段树,他可以在 $20$ 行内写完可持久化数组(如果你不去关注剩下两百行的封装代码的话)。这种简洁的美,让麦克阿瑟元帅连连称赞——“我这辈子最大的遗憾就是没有让我的士兵们学会封装代码,不过如果他们学会了封装代码,那么我敢确信他们明天就会把五角大楼打包成盒饭”

using Array = PersistentSegmentTree::PersistentArray;
const int MAXN = 1e6 + 1018 + 1108;
PersistentSegmentTree tr;
Array arrs[MAXN];
int n,q;
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>q;
	tr.size = n;
	arrs[0] = tr.NewArray();
	for(int i = 1;i <= n;i++){
		int val;
		cin>>val;
		arrs[0][i] = val;
	}
	for(int i = 1;i <= q;i++){
		int ver,opt,pos,val;
		cin>>ver>>opt;
		arrs[i] = arrs[ver];
		if(opt == 1){
			cin>>pos>>val;
			arrs[i][pos] = val;
		}else if(opt == 2){
			cin>>pos;
			cout<<arrs[i][pos]<<'\n';
		}
	}
	return not(Akano loves pure__Elysia);
}

就连 C++ 之父谭浩强也不禁赞叹“哦我的上帝,能够像 STL 一样优雅使用这种封装过的程序,是我此生最大的荣幸”

线段树也表示“如果我能早点学会 bitsetreference 设计,那么根本不会有人使用愚蠢的 Query 函数,没有人能抵挡得住操作符线段树的魅力”

while(q--){
	int opt,l,r,x;
	cin>>opt;
	if(opt == 1){
		cin>>l>>r>>x;
		tr(l,r) += x;
	}else{
		cin>>l>>r;
		cout<<tr(l,r)<<'\n';
	}
}

究竟是什么样的设计,能让如此多人沉迷于此(好像只有咱XD)?欢迎走进大型纪录片《封装传奇》

小彩蛋

#pragma once
#include<bits/stdc++.h>
using namespace std;

namespace Container{
	
	//MyAllocator : 内存分配器,预留整块的内存分配,增加分配速度减少碎片内存
	//T : 需要分配的类型种类
	//BlockNum : 每个大块包含了多少个小块,一个小块对应一个 T 的内存,也就是说一次预留多少个 T 的内存
	//Allocate() : 分配一个 T 的内存,返回指针
	//Deallocate(T* del) : 回收之前分配出去的内存,可以重复利用,传入 T指针
	//operator() : 同Allocate()
	//operator[] : 同Deallocate()
	template<typename T,int BlockNum = 10>  
	class MyAllocator{
	private:
		using Tp = T*;
		struct Block{
			unsigned char data[sizeof(T)];
			Block* next;
			Block(){
				next = nullptr;
				return ;
			}
		};
		struct Chunk{
			Block blocks[BlockNum];
			Chunk* next;
			Chunk(){
				next = nullptr;
				return ;
			}
		};
		Block* blockHead;
		Chunk* chunkHead;
		
		inline void GetMemory(){
			//创建新的Chunk
			Chunk* newChunk = new Chunk;
			blockHead = &(newChunk->blocks[0]);
			
			//把Chunk内部的后继节点设置好
			for(int i = 1;i < BlockNum;i++){
				newChunk->blocks[i - 1].next = &(newChunk->blocks[i]);
			}
			
			if(chunkHead == nullptr){
				chunkHead = newChunk;
			}else{
				newChunk->next = chunkHead;
				chunkHead = newChunk;
			}
			return ;
		}
		inline void* AllocateBlock(){//使用单块的空间
			if(blockHead == nullptr){
				GetMemory();
			}
			void* returnPointer = blockHead;
			blockHead = blockHead->next; 
			
			return returnPointer;
		}
	public:
		inline Tp Allocate(){
			int n = sizeof(T) / sizeof(T);
			Tp p = Tp(AllocateBlock());
			for(int i = 2;i <= n;i++){
				AllocateBlock();
			}
			return p;
		}
		inline void Deallocate(Tp p){
			Block* block = (Block*)(p);
			block->next = blockHead;
			blockHead = block;
			return ;
		}
		Tp operator()(){
			return Allocate();
		}
		inline void operator[](Tp p){
			Deallocate(p);
			return ;
		}
		MyAllocator(){
			blockHead = nullptr;
			chunkHead = nullptr;
			return ;
		}
		~MyAllocator(){//就是要删Chunk,无论内存怎么分配,都只有Chunk那几块
			Chunk* saveNext;
			while(chunkHead != nullptr){
				saveNext = chunkHead->next;
				delete chunkHead;
				chunkHead = saveNext;
			}
			return ;
		}
	};
	
	//SegmentTree : 支持区间加减,查询区间和的线段树 
	//T : 数值种类,只能是数字类型
	//SIZE : 线段树的大小 
	//Build() : 初始化并置初值为 0
	//Build(T arr) : 以数组为初始内容初始化
	//Change(int l,int r,int val) : 对 [l,r] 区间加上 val 的区间操作
	//Query(int l,int r) : 询问 [l,r] 区间的和
	//SegmentTree() : 初始化空的线段树
	//SegmentTree(T arr) : 以数组为初始内容初始化线段树 
	template<typename T>
	struct SegmentTreeNode{
		T val,lazy;
		int len;
		SegmentTreeNode(){val = lazy = len = 0;}
	};
	template<typename T,int SIZE>
	class SegmentTree{
		private:
			SegmentTreeNode<T> node[(SIZE + 4) * 4];
			int OBJL,OBJR,_val;
			T* arr;
			inline void PushUp(int p){
				node[p].val = node[p*2].val + node[p*2+1].val;
				return ;
			}
			inline void PushDown(int p){
				if(node[p].lazy == 0)return ;
				node[p*2].val += node[p*2].len * node[p].lazy;
				node[p*2+1].val += node[p*2+1].len * node[p].lazy;
				node[p*2].lazy += node[p].lazy,node[p*2+1].lazy += node[p].lazy;
				node[p].lazy = 0;
				return ;
			}
			void Build(int p,int l,int r){
				node[p].len = r - l + 1;
				if(l == r){
					if(arr != nullptr){
						node[p].val = arr[l];
					}
					return ;
				}
				const int mid = (l + r) >> 1;
				Build(p*2,l,mid),Build(p*2+1,mid+1,r); 
				PushUp(p);
				return ;
			}
			void ChangeInner(int p,int l,int r){
				if(OBJL <= l && r <= OBJR){
					node[p].val += _val * node[p].len;
					node[p].lazy += _val;
					return ;
				}
				const int mid = (l + r) >> 1;
				PushDown(p);
				if(mid >= OBJL)ChangeInner(p*2,l,mid);
				if(mid < OBJR)ChangeInner(p*2+1,mid+1,r);
				PushUp(p);
				return ;
			}
			T Query(int p,int l,int r){
				if(OBJL <= l && r <= OBJR){
					return node[p].val;
				}
				const int mid = (l + r) >> 1;
				T ret = 0;
				PushDown(p);
				if(mid >= OBJL)ret = Query(p*2,l,mid);
				if(mid < OBJR)ret += Query(p*2+1,mid+1,r);
				return ret;
			}
		public:
			inline void Build(){
				Build(1,1,SIZE);
				return ;
			}
			inline void Build(T* _arr){
				arr = _arr;
				Build(1,1,SIZE);
				arr = nullptr;
				return ;
			}
			inline void Change(int l,int r,int inval){
				OBJL = l,OBJR = r,_val = inval;
				ChangeInner(1,1,SIZE);
				return ;
			}
			inline T Query(int l,int r){
				OBJL = l,OBJR = r;
				return Query(1,1,SIZE);
			}
			SegmentTree(){
				Build();
				return ;
			}
			SegmentTree(T* _arr){
				Build(_arr);
				return ;
			}
	};
	
	//BIT : 支持单点修改,区间查询的树状数组
	//T : 内容的种类,要求是数字
	//SIZE : 容器大小
	//Change(int x,T val) : 给 x 位置加上 val
	//Query(int l,int r) : 询问 [l,r] 区间和 
	template<typename T,int SIZE>
	class BIT{
		private:
			T val[SIZE];
			inline int Lowbit(int x){
				return x & (-x);
			}
			inline T QueryPre(int x){
				T ret = 0;
				while(x){
					ret += val[x];
					x -= Lowbit(x);
				}
				return ret;
			}
		public:
			inline void Change(int x,T _val){
				while(x <= SIZE){
					val[x] += _val;
					x += Lowbit(x);
				}
				return ;
			}
			inline T Query(int l,int r){
				return QueryPre(r) - QueryPre(l-1);
			}
			inline void Clear(){
				memset(val,0,sizeof(val));
				return ;
			}
			BIT(){Clear();}
	};
	
	//ClearableArray : 支持清空操作过的元素的可清空数组
	//T : 内容类型,无限制
	//SIZE : 容器大小
	//operator[x] : 以下标访问内容
	//at(int x) :  代检查越界的以下标访问内容
	//Clear() : 清空从上次清空以来操作过的内容,调用 T 的构造函数 
	template<typename T,int SIZE>
	class ClearableArray{
		private:
			T _content[SIZE];
			bool _vis[SIZE];
			queue<int> clearQueue;
		public:
			T& operator[](int _x){
				if(!_vis[_x]){
					_vis[_x] = true,clearQueue.push(_x);
				}
				return _content[_x];
			}
			inline T& at(int _x){
				assert(_x < SIZE && _x >= 0);
				return operator[](_x);
			}
			inline void Clear(){
				while(!clearQueue.empty()){
					const int _u = clearQueue.front();
					clearQueue.pop();
					_vis[_u] = false;
					_content[_u] = T();
				}
				return ;
			}
			inline int Size(){
				return clearQueue.size();
			}
			ClearableArray(){
				memset(_content,0,sizeof(_content));
				memset(_vis,0,sizeof(_vis));
				return ;
			}
	};
	
	//HashMap : 哈希表,实现 unordered_map 的效果,虽然貌似少量数据情况下效率还不如 unordered_map 
	//Key : 键值,即下标的类型
	//Val : 值,存储值得类型  两者都不限
	//HashClass : 使用仿函数形式传进来的哈希函数
	//SIZE : 容器哈希值的大小,意思是说哈希值的取值范围
	//SIZE越大,越不容易产生哈希碰撞,然而并不是越大越好
	//operator[key] : 访问对应键值的值,如果没有则新建
	//HashMap(int size) : 创建一个空的 HashMap,并预留出 size 大小的空间 
	template<typename Key,typename Val>
	struct HashMapNode{
		Key key;
		Val val;
		int nxt;//索引范围int,也许需要使用更规范的类型
		HashMapNode(){key = Key(),val = Val(),nxt = 0;}
		HashMapNode(Key _key){key = _key,val = Val(),nxt = 0;}
	};
	template<typename Key,typename Val,typename HashClass,int SIZE>//SIZE一定是小于int的,索引需要装得下 
	class HashMap{
		typedef HashMapNode<Key,Val> Node;
		typedef typename vector<Node>::iterator iterator;//为了和普通容器保持一致 
		private:
			HashClass hasher = HashClass();
			ClearableArray<int,SIZE> head;
			int tot;
			vector<Node> content;
			inline int FindIndex(const Key& key){
				const int hashVal = hasher(key) % SIZE;
				for(int i = head[hashVal];i;i = content[i].nxt){
					if(content[i].key == key)return i;
				}
				return 0;
			}
			inline int Insert(const Key& key){
				const int hashVal = hasher(key) % SIZE;
				int lst = head[hashVal];
				head[hashVal] = ++tot;
				content.emplace_back(key);
				content[tot].nxt = lst;
				return tot;
			}
		public:
			iterator begin(){//方便 for(auto) 遍历 
				return ++content.begin();//初始是0,要加一个元素 
			}
			iterator end(){
				return content.end();
			}
			Val& operator[](const Key& key){
				int idx = FindIndex(key);
				if(idx == 0)idx = Insert(key);
				return content[idx].val;
			}
			inline bool Find(const Key& key){
				int idx = FindIndex(key);
				return (idx != 0);
			}
			inline void Clear(){
				content.clear();
				content.emplace_back();//初始一个空元素,下标为0,非常重要 
				head.Clear();
				tot = 0;
				return ;
			}
			HashMap(){
				Clear();
				return ;
			}
			HashMap(int initVal){
				content.reserve(initVal);
				Clear();
				return ;
			}
	};
	
	//HashSet : 哈希表,实现 unordered_set 的功能
	//Val,HashClass,SIZE : 同 HashMap 
	//Insert(Val val) : 插入值,返回插入是否成功(是否已有该元素) 
	//Find(Val val) : 查询是否已有该元素
	template<typename Val>
	struct HashSetNode{
		Val val;
		int nxt;
		HashSetNode(){val = Val(),nxt = 0;}
		HashSetNode(Val _val){val = _val,nxt = 0;}
	};
	template<typename Val,typename HashClass,int SIZE>
	class HashSet{
		typedef HashSetNode<Val> Node;
		typedef typename vector<Node>::iterator iterator;
		private:
			HashClass hasher = HashClass();
			ClearableArray<int,SIZE> head;
			int tot;
			vector<Node> content;
			inline int FindIndex(const Val& val){
				const int hashVal = hasher(val) % SIZE;
				for(int i = head[hashVal];i;i = content[i].nxt){
					if(content[i].val == val)return i;
				}
				return 0;
			}
			inline int InsertContent(const Val& val){
				const int hashVal = hasher(val) % SIZE;
				int lst = head[hashVal];
				head[hashVal] = ++tot;
				content.emplace_back(val);
				content[tot].nxt = lst;
				return tot;
			}
		public:
			iterator begin(){//方便 for(auto) 遍历 
				return ++content.begin();//初始是0,要加一个元素 
			}
			iterator end(){
				return content.end();
			}
			inline bool Insert(const Val& val){
				int idx = FindIndex(val);
				if(idx)return false;
				InsertContent(val);
				return true;
			}
			inline bool Find(const Val& val){
				int idx = FindIndex(val);
				return (idx != 0);
			}
			inline void Clear(){
				content.clear();
				content.emplace_back();//初始一个空元素,下标为0,非常重要 
				head.Clear();
				tot = 0;
				return ;
			}
			HashSet(){//初始一个空元素,下标为0,非常重要 
				Clear();
				return ;
			}
			HashSet(int initVal){//初始一个空元素,下标为0,非常重要 
				content.reserve(initVal);
				Clear();
				return ;
			}
	};
	
	//自定义Vector,你问咱有什么用?下标从1开始,无了()(硬要说的话更符合咱的代码习惯)
	//PushBack,Empty,Reserve,Resize,Clear,operator[] 同 vector
	//Free = Resize(1),shink_to_fit (释放内存)
	template<typename T>
	class Vector{
		private:
			const static int Exsize = 2;
			T* content;
			inline void SetCapacity(size_t newSize){
				T* newContent = new T[newSize+1];
				memcpy(newContent,content,sizeof(T) * min((size+1),newSize));
				swap(newContent,content);
				delete[] newContent;
				capacity = newSize;
				size = min(size,capacity);
				return ;
			}
			inline void Shift(int x){
				if(size + x > capacity){
					SetCapacity(size + x); 
				}
				if(x > 0){
					for(size_t i = size;i >= 1;i--){
						content[i+x] = content[i];
					}
					for(size_t i = 1;i <= size_t(x);i++)content[i] = T();
					size += x;
				}
				if(x < 0){
					x = -x;
					for(size_t i = size_t(x+1);i <= size;i++){
						content[i-x] = content[i];
					}
					for(size_t i = size_t(size-x+1);i <= size;i++)content[i] = T();
					size -= x;
				}
				return ;
			}
		public:
			size_t capacity,size;
			typedef T* iterator;
			inline iterator begin(){
				return &content[1];
			}
			inline iterator end(){
				return &content[size+1];
			}
			inline void PushBack(const T& newContent){
				if(size + 1 > capacity){
					SetCapacity(capacity * Exsize); 
				}
				content[++size] = newContent;
				return ;
			}
			inline void PopBack(){
				if(size >= 1)size--;
				return ;
			}
			inline void PushFront(const T& newContent){//O(n)......
				Shift(1);
				content[1] = newContent;
				return ;
			}
			inline void PopFront(){//O(n)......
				Shift(-1);
				return ;
			}
			inline bool Empty(){
				return (size == 0);
			}
			inline void Reserve(size_t newSize){
				if(newSize > capacity)SetCapacity(newSize);
				return ;
			}
			inline void Resize(size_t newSize){
				if(capacity < newSize)SetCapacity(newSize);
				size = newSize;
				return ;
			}
			inline void Clear(){
				size = 0;
				return ;
			}
			inline void Free(){
				SetCapacity(1);
				size = 0;
				return ;
			}
			T& operator[](size_t x){
				return content[x];
			}
			Vector(){
				content = new T[2];
				content[0] = T();
				capacity = 1,size = 0;
				return ;
			}
	};
	
	//新版本迭代器Treap
	//更新注释:比起上个版本灾难性的史山Treap好一万倍的Treap,真正意义上支持了迭代器,效率更高
	//效率相比 set 来说,保守估计2倍常数,实际1.5倍左右(但它可以查排名啊)
	//Treap::iterator 类
	//注释 : 目前为 private 类,无法通过 Treap::iterator 获取,只能使用 auto 接受
	//operator *() : 解引用值,然而虽然返回的是引用但是如果修改值的话会破坏 Treap 性质,并不支持修改(可以在之后加上Update的机制)
	//operator ++/--(前后自加减) : 获得该迭代器位置的前驱和后继,有均摊复杂度 O(1) 的特性,单次最坏 O(log n)
	//operator ==/!= : 判等
	//Treap 成员函数
	//begin() / end() 获得 STL 同意义的 begin/end,因此支持 for(auto) 范围for
	//Insert(T val) : 插入值,如果元素已存在则挂载一个副本在原元素上,共享一个迭代器
	//Delete(T val) : 删除值,如果存在多个只删除一个
	//GetRank(T val) : 获取某值的排名(从小到大第几个),从 1 开始
	//GetVal(int k) : 获得第 k 大的值
	//Find(T val) : 获得 val 的迭代器,不存在返回 end()
	//GetPre(T val) : 获得 val 的严格前驱(val 对应的节点不一定存在,不然推荐使用 iterator--)(实现较为暴力,常数较大)
	//GetNext(T val) : 获得 val 的严格后继
	template<typename T>
	class Treap{
	private:
		const static int keyINF = 1e9;
		const static int chunkSize = 100;//可能导致容器最小大小变大,要默认大小为 100个T 的大小
		struct Node;
		struct iterator;
		using Nodep = Node*;
		Nodep emptyp;
		struct Node{
			int key,tot,sz;
			T val;
			Nodep l,r,fa;
			Node(){//不提供带参数的构造函数了,反正也没用
				key = tot = sz = 0;
				val = T();
				l = r = fa = nullptr;//注意,不应该使用默认构造函数!!!
			}
		};
		iterator beginItor,endItor;
		class iterator{
		private:
			friend class Treap;
			Node* node;
			Treap* source;
			iterator(){
				source = nullptr;
				node = nullptr;
				return ;
			}
			iterator(Nodep _node,Treap* _source){
				source = _source;
				node = _node;
				return ;
			}
		public:
			T& operator*(){
				return node->val;
			}
			bool operator==(iterator it){
				return source == it.source && node == it.node;
			}
			bool operator!=(iterator it){
				return !(*this == it);
			}
			iterator& operator++(){
				//需要模拟中序遍历
				Nodep pos = node,last = node->l;
				//现在遍历完左子树,尝试遍历右子树
				if(pos->r != source->emptyp){
					pos = pos->r;
					while(pos->l != source->emptyp){
						pos = pos->l;
					}
					node = pos;
					return *this;
				}
				//遍历完了(没找到),往父亲跳
				last = node,pos = node->fa;
				while(pos != source->emptyp){
					if(last == pos->l){//中序遍历遍历到自己
						node = pos;
						return *this;
					}
					//last == node->r : 中序遍历完了该节点,放回父亲
					last = pos,pos = pos->fa;
				}
				if(pos == source->emptyp)*this = source->endItor;
				return *this;
			}
			iterator operator++(int){//可以这么写吗?? 
				iterator old = *this;
				operator++();
				return old;
			}
			iterator& operator--(){
				//反向模拟中序遍历
				Nodep pos = node,last = node->l;
				//尝试遍历左子树
				if(pos->l != source->emptyp){
					pos = pos->l;
					while(pos->r != source->emptyp){
						pos = pos->r;
					}
					node = pos;
					return *this;
				}
				//遍历完了(没找到),往父亲跳
				last = node,pos = node->fa;
				while(pos != source->emptyp){
					if(last == pos->r){//中序遍历遍历到自己
						node = pos;
						return *this;
					}
					last = pos,pos = pos->fa;
				}
				if(pos == source->emptyp)*this = source->endItor;
				return *this;
			}
			iterator operator--(int){
				iterator old = *this;
				operator--();
				return old;
			}
		};
		
		mt19937 rander;
		Nodep root;
		MyAllocator<Node,chunkSize> myAllocator;
		
		inline void PushUp(Nodep p){
			p->sz = p->l->sz + p->r->sz + p->tot;
			p->l->fa = p->r->fa = p;
			return ;
		}
		inline void Zag(Nodep& p){//左旋 
			Nodep q = p->r;
			p->r = q->l;
			q->l = p;
			p = q;
			PushUp(p);
			PushUp(p->l);
			return ;
		}
		inline void Zig(Nodep& p){//右旋 
			Nodep q = p->l;
			p->l = q->r;
			q->r = p;
			p = q;
			PushUp(p);
			PushUp(p->r);
			return ;
		}
		iterator Insert(Nodep& p,T val){
			if(p == emptyp){
				p = myAllocator.Allocate();
				p->val = val,p->key = rander() % keyINF,p->l = p->r = p->fa = emptyp;
				p->tot = p->sz = 1;
				//更新beginItor,最小值一定插入在前最小值的左儿子
				if(beginItor.node == emptyp || p == beginItor.node->l){
					beginItor.node = p;
				}
				return iterator(p,this);
			}
			iterator ret;
			if(val == p->val){
				p->tot++;
				ret = iterator(p,this);
			}else if(val < p->val){
				ret = Insert(p->l,val);
				if(p->key < p->l->key){
					Zig(p);
				}
			}else{
				ret = Insert(p->r,val);
				if(p->key < p->r->key){
					Zag(p);
				}
			}
			PushUp(p);
			return ret;
		}
		void Delete(Nodep& p,T val){
			if(p == emptyp)return ;
			if(p->val == val){
				if(p->tot >= 2){
					--p->tot;
				}else if(p->l != emptyp || p->r != emptyp){
					if(p->l->key > p->r->key){
						Zig(p);
						Delete(p->r,val);
					}else{
						Zag(p);
						Delete(p->l,val);
					}
				}else{
					//更新beginItor,新最小值一定是现最小值的父亲
					if(p == beginItor.node){
						beginItor.node = p->fa;
					}
					myAllocator.Deallocate(p);
					p = emptyp;
				}
			}else if(val < p->val){
				Delete(p->l,val); 
			}else if(val > p->val){
				Delete(p->r,val);
			}
			PushUp(p);
			return ;
		}
		int GetRank(Nodep p,T val){
			if(p == emptyp)return 1;
			if(val == p->val){
				return p->l->sz + 1;
			}else if(val < p->val){
				return GetRank(p->l,val);
			}else if(val > p->val){
				return GetRank(p->r,val) + p->tot + p->l->sz;
			}
			return 10181108;
		}
		iterator GetVal(Nodep p,T k){
			if(k <= p->l->sz){
				return GetVal(p->l,k);
			}else if(k <= int(p->l->sz + p->tot)){
				return iterator(p,this);
			}
			return GetVal(p->r,k - p->l->sz - p->tot);
		}
		iterator Find(Nodep p,T val){
			if(p == emptyp)return endItor;
			if(p->val == val)return iterator(p,this);
			if(val < p->val){
				return Find(p->l,val);
			}else{
				return Find(p->r,val);
			}
			return endItor;
		}
	public:
		inline iterator begin(){
			return beginItor;
		}
		inline iterator end(){
			return endItor;
		}
		inline iterator Insert(T val){
			return Insert(root,val);
		}
		inline void Delete(T val){
			Delete(root,val);
			return ;
		}
		inline int GetRank(T val){
			return GetRank(root,val); 
		}
		inline iterator GetVal(int k){
			return GetVal(root,k);
		}
		inline iterator Find(T val){
			return Find(root,val);
		}
		inline iterator GetPre(T val){
			auto itor = Insert(val);
			--itor;
			Delete(val);
			return itor;
		}
		inline iterator GetNext(T val){
			auto itor = Insert(val);
			++itor;
			Delete(val);
			return itor;
		}
		Treap(){
			emptyp = new Node();
			emptyp->sz = emptyp->tot = 0;
			emptyp->l = emptyp->r = emptyp;//自指没问题吧
			root = emptyp;
			beginItor = iterator(emptyp,this);
			endItor = iterator(emptyp,this);
			rander.seed(time(0));
			return ;
		}
		~Treap(){
			//DeleteDFS(root);
			//貌似不用DeleteDFS,因为Alloc分配的内存无论如何都会被删掉
			//并不要求需要Deallocate回去才可以回收
			delete emptyp;//只有这个可以直接delete,也需要delete
			return ;
		}
	};
	
	//Trmap : treap : map
	//极其简陋的 treap 封装实现 map 功能
	//目前功能较少,稳定性未知
	//operator[] : map式的访问
	template<typename keyT,typename valT>
	class Trmap{
	private:
		struct Node{
			keyT key;
			valT val;
			bool operator==(Node oth){
				return key == oth.key;
			}
			bool operator<(Node oth){
				return key < oth.key;
			}
		};
		Treap<Node> treap;
	public:
		valT& operator[](const keyT& _key){
			Node node = {_key,valT()};
			auto it = treap.Find(node);
			if(it == treap.end())it = treap.Insert(node);
			return (*it).val;
		}
	};
}
此作者没有提供个人介绍。
最后更新于 2026-09-10