无旋Treap(struct+指针)实现

#include <iostream>
#include <tuple>

using namespace std;

struct node {
	node *l,*r;
	int val, pri;
	int cnt;
	int siz;
	node(int _val) {
		val = _val;
		siz = cnt = 1;
		pri = rand();
		l = r = nullptr;
	}
	void update() {
		siz = cnt;
		if (l != nullptr) 
			siz += l->siz;
		if (r != nullptr) 
			siz += r->siz;
	}
};
struct fhq_treap {
	node *root;
	pair<node *, node *> split(node *u, int val) {
		//按值分裂
		//分裂操作是将一个 Treap 分成 x,y 两个 Treap。其中 x 中每一个结点的值都小于等于 k,而 y 中每一个结点的值都大于等于 k。
		if (u == nullptr) 
			return {nullptr, nullptr};
		if (u->val <= val) {
			//说明其左子树肯定都<=k,在x中,但是在右子树中仍然可能存在值比k小的节点(但肯定比u的值大),所以要继续递归分裂
			auto tmp = split(u->r, val);
			u->r = tmp.first;
			//将右子树中<=k的部分拿出来作为u的右子树,这样整个u都是<=k的,剩下的都是大于于k的
			u->update();
			return {u, tmp.second};
		} 
		else {
			//同上
			auto tmp = split(u->l, val);
			u->l = tmp.second;
			u->update();
			return {tmp.first, u};
		}
	}
	
	tuple<node *, node *, node *> splitrnk(node *u, int rnk) {
		//按排名分裂,与按照值分裂类似,只是这里分成了三部分:排名<rnk的,
		//排名=rnk的(并且第二个 treap即排名=rnk的 只有一个节点(不可能有多个等于的,如果有的话会增加 node 结构体中的 cnt)),以及排名>rnk的
		if (u == nullptr) 
			return {nullptr, nullptr, nullptr};
		int lsiz = u->l == nullptr ? 0 : u->l->siz;
		if (rnk <= lsiz) {
			// 排名和 u 相等的节点在左子树
			node *l, *mid, *r;
			tie(l, mid, r) = splitrnk(u->l, rnk);
			u->l = r;
			// 返回的第三个 treap 中的排名都大于 rnk
			// u 的左子树被设成 r 后,整个 cur 中节点的排名都大于 rnk(即剥离左子树)
			u->update();
			return {l, mid, u};
		} 
		else if (rnk <= lsiz + u->cnt) {
			// 和 u 相等的就是当前节点
			node *ltr = u->l;
			node *rtr = u->r;
			u->l = u->r = nullptr;
			// 分裂后第二个 treap 只有一个节点,所有要把它的子树设置为空
			return {ltr, u, rtr};
		} 
		else {
			// 排名和 u 相等的节点在右子树
			//同上
			node *l, *mid, *r;
			tie(l, mid, r) = splitrnk(u->r, rnk - lsiz - u->cnt);
			u->r = l;
			u->update();
			return {u, mid, r};
		}
	}
	node *merge(node *u, node *v) {
		//将分裂后的子树再次合并起来
		//一般来说,我们合并的两个 treap 都是原来从一个 treap 中分裂出去的,所以不难满足u中所有节点的值都小于 𝑣
		//即传进来的两个树的内部已经符合搜索树的性质了
		// 并且 u 内所有节点的值 < v 内所有节点的值
		// 所以在合并的时候需要维护堆的性质
		// 这里用的是小根堆
		if (u == nullptr)
			return v;
		if (v == nullptr)
			return u;
		if (u->pri < v->pri) {
			// u 的 pri 比较小,u应该作为父节点
			u->r = merge(u->r, v);
			// 因为 v 比 u 大,所以把 v 作为 u 的右子树
			u->update();
			return u;
		} 
		else {
			//同理
			v->l = merge(u, v->l);
			v->update();
			return v;
		}
	}
	void insert(int val) {
		//插入一个元素就是要找到对应值的节点的位置,并使该节点的“数量”即cnt+1(没有就创建新的)
		auto tmp = split(root, val);
		auto ltr = split(tmp.first, val - 1);
		//找到对应的位置,注意,左子树<=val,右子树>val
		if (ltr.second == nullptr)
			ltr.second = new node(val);
		else {
			ltr.second->cnt++;
			ltr.second->update();
		}
		root = merge(merge(ltr.first, ltr.second), tmp.second);
		//所有的分裂操作不要忘记合并回来
	}
	void erase(int val) {
		//删除一个元素就是要找到对应值的节点的位置,并使该节点的“数量”即cnt-1(刚好为1就完全删除,即设为nullptr)
		auto tmp = split(root, val);
		auto ltr = split(tmp.first, val - 1);
		//同插入
		if (ltr.second->cnt > 1) {
			ltr.second->cnt--;
			ltr.second->update();
		} 
		else {
			if (tmp.first == ltr.second)
				//有可能整个 tmp.first 只有这个节点,所以也需要把这个点设成 nullptr 来标注已经删除
				tmp.first = nullptr;
			ltr.second = nullptr;
		}
		root = merge(merge(ltr.first, ltr.second), tmp.second);
	}
	int queryrank(node *u, int val) {//根据值查找排名
		//排名是比这个值小的节点的数量 +1 所以我们根据 val−1分裂当前树,那么分裂后的第一个树就符合:Tree(left)<=val-1,直接返回其大小+1即可(前提为整数)
		auto tmp = split(u, val - 1);
		int res = (tmp.first == nullptr ? 0 : tmp.first->siz) + 1;
		root = merge(tmp.first, tmp.second);
		return res;
	}
	int queryval(node *u, int rnk) {//根据排名查找值
		//直接让根据排名分裂发力
		node *l, *mid, *r;
		tie(l, mid, r) = splitrnk(u, rnk);
		int res = mid->val;
		root = merge(merge(l, mid), r);
		return res;
	}
	int getpre(int val) {
		//前驱就是比val排名小的元素里最大的
		auto tmp = split(root, val - 1);
		int res = queryval(tmp.first, tmp.first->siz);
		root = merge(tmp.first, tmp.second);
		return res;
	}
	int getnext(int val) {
		//后驱就是比val排名大的元素里最小的
		auto tmp = split(root, val);
		int res = queryval(tmp.second, 1);
		root = merge(tmp.first, tmp.second);
		return res;
	}
};
fhq_treap tr;

int main() {
	cin.tie(nullptr) -> sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--) {
		int opt, x;
		cin >> opt >> x;
		switch (opt) {
		case 1:
			tr.insert(x);
			break;
		case 2:
			tr.erase(x);
			break;
		case 3:
			cout << tr.queryrank(tr.root, x) << '\n';
			break;
		case 4:
			cout << tr.queryval(tr.root, x) << '\n';
			break;
		case 5:
			cout << tr.getpre(x) << '\n';
			break;
		case 6:
			cout << tr.getnext(x) << '\n';
			break;
		}
	}
}
/*
#include<bits/stdc++.h>

using namespace std;

const int N=1100010;
struct Pair{
	int l,r;
	Pair(int l_=0,int r_=0): l(l_),r(r_){}
};
struct node{
	int l,r,pri,val,siz;
};
node tree[N];
int tot,root;
int n,m;

inline void pushup(int u){
	tree[u].siz=tree[tree[u].l].siz+tree[tree[u].r].siz+1;
}
Pair splitval(int u,int k){
	if(!u) return {0,0};
	if(tree[u].val<=k){
		auto tmp=splitval(tree[u].r,k);
		tree[u].r=tmp.l;
		pushup(u);
		return {u,tmp.r};
	}
	else{
		auto tmp=splitval(tree[u].l,k);
		tree[u].l=tmp.r;
		pushup(u);
		return {tmp.l,u};
	}
}
int merge(int u,int v){
	if(!u || !v) return u+v;
	if(tree[u].pri<tree[v].pri){
		tree[u].r=merge(tree[u].r,v);
		pushup(u);
		return u;
	}
	else{
		tree[v].l=merge(u,tree[v].l);
		pushup(v);
		return v;
	}
}
void insert(int k){
	tree[++tot].val=k;
	tree[tot].siz=1;
	tree[tot].pri=rand();
	tree[tot].l=tree[tot].r=0;
	auto tmp=splitval(root,k-1);
	root=merge(tmp.l,merge(tot,tmp.r));
}
void erase(int k){
	auto x=splitval(root,k-1);
	auto y=splitval(x.r,k);
	y.l=merge(tree[y.l].l,tree[y.l].r);
	root=merge(x.l,merge(y.l,y.r));
}
int queryrank(int k){
	auto tmp=splitval(root,k-1);
	int res=tree[tmp.l].siz+1;
	root=merge(tmp.l,tmp.r);
	return res;
}
int queryval(int k){
	int pos=root;
	while(pos){
		if(k==tree[tree[pos].l].siz+1) return tree[pos].val;
		if(k<tree[tree[pos].l].siz+1) pos=tree[pos].l;
		else{
			k-=tree[tree[pos].l].siz+1;
			pos=tree[pos].r;
		}
	}
	return 0x3f3f3f3f;
}
int getpre(int k){
	return queryval(queryrank(k)-1);
}
int getnext(int k){
	return queryval(queryrank(k+1));
}

int main() {
	cin.tie(nullptr)->sync_with_stdio(false);
	cin>>n>>m;
	for (int i = 1; i <= n; ++i) {
		int tmp;
		cin>>tmp;
		insert(tmp);
	}
	
	int last=0,ans=0;
	for (int i = 1; i <= m; ++i) {
		int opt,x;
		cin>>opt>>x;
		if (opt == 1) insert(x^last);
		if (opt == 2) erase(x^last);
		if (opt == 3) {
			last = queryrank(x^last);
			ans ^= last;
		}
		if (opt == 4) {
			last = queryval(x^last);
			ans ^= last;
		}
		if (opt == 5) {
			last = getpre(x^last);
			ans ^= last;
		}
		if (opt == 6) {
			last = getnext(x^last);
			ans ^= last;
		}
//		cout<<last<<'\n';
	}
	
	cout<<ans<<'\n';
	return 0;
}
*/
#include<iostream>
#include<random>

using namespace std;

mt19937 Rand(time(nullptr));
struct node{
	node *l,*r;
	int val,siz,pri;
	
	node(int _val): l(nullptr),r(nullptr),val(_val),siz(1),pri(Rand()){}
	void pushup(){
		siz=1;
		if(l!=nullptr)
			siz+=l->siz;
		if(r!=nullptr)
			siz+=r->siz;
	}
};
struct fhq_treap{
	node *root;
	pair<node *,node *> splitval(node *u,int val){
		if(u==nullptr)
			return {nullptr,nullptr};
		if(u->val<=val){
			auto tmp=splitval(u->r,val);
			u->r=tmp.first;
			u->pushup();
			return {u,tmp.second};
		}
		else{
			auto tmp=splitval(u->l,val);
			u->l=tmp.second;
			u->pushup();
			return {tmp.first,u};
		}
	}
	node *merge(node *u,node *v){
		if(u==nullptr)
			return v;
		if(v==nullptr)
			return u;
		if(u->pri<v->pri){
			u->r=merge(u->r,v);
			u->pushup();
			return u;
		}
		else{
			v->l=merge(u,v->l);
			v->pushup();
			return v;
		}
	}
	void insert(int val){
		auto tmp=splitval(root,val-1);
		auto newnode=new node(val);
		root=merge(merge(tmp.first,newnode),tmp.second);
	}
	void erase(int val){
		auto tmp=splitval(root,val-1);
		auto rtr=splitval(tmp.second,val);
		rtr.first=merge(rtr.first->l,rtr.first->r);
		root=merge(tmp.first,merge(rtr.first,rtr.second));
	}
	int queryrank(int val){
		auto tmp=splitval(root,val-1);
		int res=tmp.first==nullptr? 1:tmp.first->siz+1;
		root=merge(tmp.first,tmp.second);
		return res;
	}
	int queryval(int rnk){
		auto pos=root;
		while(pos!=nullptr){
			int lsiz=pos->l==nullptr? 0:pos->l->siz;
			if(rnk==lsiz+1)
				return pos->val;
			if(rnk<lsiz+1)
				pos=pos->l;
			else{
				rnk-=lsiz+1;
				pos=pos->r;
			}
		}
		return pos==nullptr? 0:pos->val;
	}
	int getpre(int val){
		return queryval(queryrank(val)-1);
	}
	int getnext(int val){
		return queryval(queryrank(val+1));
	}
};
fhq_treap tr;

int main(){
	cin.tie(nullptr)->sync_with_stdio(false);
	int n,m;
	cin>>n>>m;
	for (int i = 1; i <= n; ++i) {
		int tmp;
		cin>>tmp;
		tr.insert(tmp);
	}
	
	int last=0,ans=0;
	for (int i=1;i<=m;++i){
		int opt,x;
		cin>>opt>>x;
		if (opt==1) 
			tr.insert(x^last);
		if (opt==2) 
			tr.erase(x^last);
		if (opt==3) {
			last=tr.queryrank(x^last);
			ans^=last;
		}
		if (opt==4) {
			last=tr.queryval(x^last);
			ans^=last;
		}
		if (opt==5) {
			last=tr.getpre(x^last);
			ans^=last;
		}
		if (opt==6) {
			last=tr.getnext(x^last);
			ans^=last;
		}
	}
	
	cout<<ans<<'\n';
}
posted @ 2025-09-28 20:24  _CENSORED  阅读(6)  评论(1)    收藏  举报