无旋treap学习

无旋 treap 学习

原理

前言

  • t r e a p = t r e e + h e a p treap=tree+heap treap=tree+heap,其在 BST (二叉搜索树) 的基础上,多添加了一个参数 key ,通过维护 key 的二叉堆性质,来使得 t r e a p treap treap 的期望高度达到 l o g n logn logn
  • 核心 s p l i t split split m e r g e merge merge 。通过 s p l i t split split 将一棵 t r e a p treap treap 拆分成一棵值均 < = v a l <=val <=val t r e a p treap treap 和一棵值均 > = v a l >=val >=val t r e a p treap treap 。通过 m e r g e merge merge 将分好的两棵 t r e a p treap treap 合并成一棵具有二叉堆性质的二叉搜索树。

split

void split(int now,int &a,int &b,int val) {
	if(now==0) {
		a=b=0;
		return;
	}
	if(tr[now].val<=val)a=now,split(tr[now].r,tr[a].r,r,val);
	else b=now,split(tr[now].l,a,tr[b].l,val);
	pushup(now);
}

merge

void merge(int &now,int a,int b) {//把已 a 为根的树和已 b 为根的树合并为以 now 为根的树
		if(a==0||b==0) {
			now=a+b;
			return;
		}
		if(tr[a].val>tr[b].val)now=a,merge(tr[now].r,tr[a].r,r);
		else now=b,merge(tr[now].l,a,tr[b].l);
		pushup(now);
	}

维护数值模板

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;

struct Treap {
	int root,cnt;
	struct node {
		int val,key,l,r,size;
	} tr[N];
	Treap() {
		root=cnt=0;
	}
	void pushup(int now) {
		tr[now].size=tr[tr[now].l].size+tr[tr[now].r].size+1;
	}
	int newnode(int val) {
		tr[++cnt].val=val;
		tr[cnt].l=tr[cnt].r=0;
		tr[cnt].size=1;
		tr[cnt].key=rand();
		return cnt;
	}
	void split(int now,int &a,int &b,int val) {
		if(now==0) {
			a=b=0;
			return;
		}
		if(tr[now].val<=val)a=now,split(tr[now].r,tr[a].r,b,val);
		else b=now,split(tr[now].l,a,tr[b].l,val);
		pushup(now);
	}
	void merge(int &now,int a,int b) {//把已 a 为根的树和已 b 为根的树合并为以 now 为根的树
		if(a==0||b==0) {
			now=a+b;
			return;
		}
		if(tr[a].key>tr[b].key)now=a,merge(tr[now].r,tr[a].r,b);
		else now=b,merge(tr[now].l,a,tr[b].l);
		pushup(now);
	}
	void insert(int val) {
		int x=0,y=0;
		split(root,x,y,val-1);
		merge(x,x,newnode(val));
		merge(root,x,y);
	}
	void del(int val) {
		int x=0,y=0,z=0;
		split(root,x,y,val);
		split(x,x,z,val-1);
		merge(z,tr[z].l,tr[z].r);
		merge(x,x,z);
		merge(root,x,y);
	}
	int rnk(int val) {
		int x=0,y=0;
		split(root,x,y,val-1);
		int ans=tr[x].size+1;
		merge(root,x,y);
		return ans;
	}
	int kth(int k) {
		int now=root;
		while(1) {
			if(k==tr[tr[now].l].size+1)return tr[now].val;
			if(k<=tr[tr[now].l].size)now=tr[now].l;
			else k-=tr[tr[now].l].size+1,now=tr[now].r;
		}
	}
	int pre(int val) {
		int x=0,y=0;
		split(root,x,y,val-1);
		int ans=tr[x].val;
		merge(root,x,y);
		return ans;
	}
	int suf(int val) {
		int x=0,y=0;
		split(root,x,y,val);
		int size=tr[x].size+1;
		merge(root,x,y);
		return kth(size);
	}
};

维护序列,动态数组模板

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;

struct Treap {
	int root,cnt;
	struct node {
		int val,key,l,r,size,tag;
	} tr[N];
	Treap() {
		root=cnt=0;
	}
	void pushup(int now) {
		tr[now].size=tr[tr[now].l].size+tr[tr[now].r].size+1;
	}
	void pushdown(int now){
		if(tr[now].tag){
			swap(tr[now].l,tr[now].r);
			tr[now].tag^=1;
			if(tr[now].l)tr[tr[now].l].tag^=1;
			if(tr[now].r)tr[tr[now].r].tag^=1;
		}
	}
	int newnode(int val) {
		tr[++cnt].val=val;
		tr[cnt].l=tr[cnt].r=tr[cnt].tag=0;
		tr[cnt].size=1;
		tr[cnt].key=rand();
		return cnt;
	}
	void split(int now,int &a,int &b,int x) {//维护序列问题用这个,分出来的第 1 棵树切好有 x 个结点
		if(now==0) {
			a=b=0;
			return;
		}
		pushdown(now);
		if(tr[tr[now].l].size+1<=x)a=now,split(tr[now].r,tr[a].r,b,x-tr[tr[now].l].size-1);
		else b=now,split(tr[now].l,a,tr[b].l,x);
		pushup(now);
	}
	void merge(int &now,int a,int b) {//把已 a 为根的树和已 b 为根的树合并为以 now 为根的树
		if(a==0||b==0) {
			now=a+b;
			return;
		}
		pushdown(a);
		pushdown(b);
		if(tr[a].key>tr[b].key)now=a,merge(tr[now].r,tr[a].r,b);
		else now=b,merge(tr[now].l,a,tr[b].l);
		pushup(now);
	}
	void insert(int pos,int val) {//在第 pos 个位置后面插入一个元素 val 
		int x=0,y=0;
		split(root,x,y,pos);
		merge(x,x,newnode(val));
		merge(root,x,y);
	}
	void del(int pos) {//删除第 pos 个位置 
		int x=0,y=0,z=0;
		split(root,x,y,pos);
		split(x,x,z,pos-1);
		merge(root,x,y);
	}
	int operator[] (int pos){
		int x=0,y=0,z=0;
		split(root,x,y,pos);
		split(x,x,z,pos-1);
		int ans=tr[z].val;
		merge(x,x,z);
		merge(root,x,y);
		return ans;
	}
	void write(int now){
		if(now==0)return;
		write(tr[now].l); 
		cout<<tr[now].val<<" ";
		write(tr[now].r);
	}
	void write(){
		write(root);
	}
	void reserve(int l,int r){
		int x=0,y=0,z=0;
		split(root,x,y,l-1);
		split(y,y,z,r-l+1);
		tr[y].tag^=1;
		merge(y,y,z);
		merge(root,x,y);
	}
	void gonext(int l,int r){
		int x=0,y=0,z=0,t=0;
		split(root,x,y,l-1);
		split(y,y,z,r-l);
		split(z,z,t,1);
        //[1,l-1],[l,r-1],[r,r],[r+1,n]
		merge(y,y,t);
		merge(z,z,y);
		merge(root,x,z);
	}
} tr;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值