ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

fhq treap总结

2021-07-07 20:01:24  阅读:204  来源: 互联网

标签:总结 ch val int treap split now fhq


学完fhq treap后决定发篇总结
我学习的是这篇题解,代码也是模仿这位大佬的

备注:文本可能有一些看不懂的地方,可以仔细看代码模拟,非常有助于理解

treap是一种平衡树,既满足二叉搜索树的性质,也满足小根堆的性质

treap上每个节点有val值和key值。

val值是我们需要的权值,在treap上val值满足二叉搜索树的性质,也就是每个节点的val值大于其左子树中所有节点的val值,小于其右子树中所有节点的val值。

key值是我们用rand()随机给的,在treap上key值满足小根堆的性质,也就是每个节点的key值小于其子树中所有节点的key值。

接下来着重介绍一下treap的两个基本操作:merge和split,借助这两个操作可以达到一般平衡树能达到的所有功能

1.split

这个函数的功能是把一个treap按权值分成两个,有两种形式,一种按权值k划分,一种按权值排名k划分

1.权值版

void split(int now,int k,int &x,int &y){
	if(!now)x=y=0;
	else {
		if(val[now]<=k)
			x=now,split(ch[now][1],k,ch[now][1],y);
		else 
			y=now,split(ch[now][0],k,x,ch[now][0]);
		update(now);
	}
}

x,y是指向左右两颗新树的下一个儿子,如果该节点的val<=k,把该点连同左子树接到左新树上,继续split右子树,否则反之。以val<=k为例,因为右子树中所有节点val值都比该节点大,所有我们可以把以后val<=k的节点放心的接到x的右子树上,也就是把x指向ch[now][1]

2.k大版

void split_kth(int now,int k,int &x,int &y){
	if(!now)x=y=0;
	else {
		if(k>sz[ch[now][0]])
			x=now,split_kth(ch[now][1],k-sz[ch[now][0]]-1,ch[now][1],y);
		else
			y=now,split_kth(ch[now][0],k,x,ch[now][0]);
		update(now);
	}
}

有点类似找第k大,其他的部分与权值版类似

2.merge

这个函数的功能是把两个treap合并,且前一个treap中所有点的权值小于后一个

int merge(int x,int y){
	if(!x||!y)return x|y;
	if(key[x]<key[y]){
		ch[x][1]=merge(ch[x][1],y);
		update(x);
		return x;
	}
	else {
		ch[y][0]=merge(x,ch[y][0]);
		update(y);
		return y;
	}
}

因为比较简单就不做解释了,可以看上述大佬的题解

代码

下面是洛谷P3369普通平衡树的代码,给出了treap的常见函数

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int M=1e5+5,P=1e9+7,base=269;
inline int rd(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){
		if(c=='-')f=-1;
		c=getchar();
	}while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,ch[M][2],val[M],sz[M],key[M],tot,rt;
inline int Rand(){return 1ll*rand()*rand()%P;}
inline void update(int p){sz[p]=1+sz[ch[p][0]]+sz[ch[p][1]];}
int new_node(int v){
	sz[++tot]=1;
	key[tot]=Rand();
	val[tot]=v;
	return tot;
}
void split(int now,int k,int &x,int &y){
	if(!now)x=y=0;
	else {
		if(val[now]<=k)
			x=now,split(ch[now][1],k,ch[now][1],y);
		else 
			y=now,split(ch[now][0],k,x,ch[now][0]);
		update(now);
	}
}
void split_kth(int now,int k,int &x,int &y){
	if(!now)x=y=0;
	else {
		if(k>sz[ch[now][0]])
			x=now,split_kth(ch[now][1],k-sz[ch[now][0]]-1,ch[now][1],y);
		else
			y=now,split_kth(ch[now][0],k,x,ch[now][0]);
		update(now);
	}
}
int merge(int x,int y){
	if(!x||!y)return x|y;
	if(key[x]<key[y]){
		ch[x][1]=merge(ch[x][1],y);
		update(x);
		return x;
	}
	else {
		ch[y][0]=merge(x,ch[y][0]);
		update(y);
		return y;
	}
}
void insert(int &p,int v){
	int x=0,y=0;
	split(p,v,x,y);
	p=merge(merge(x,new_node(v)),y);
}
void del(int &p,int v){
	int x=0,y=0,z=0;
	split(p,v,x,y);
	split_kth(x,sz[x]-1,x,z);
	p=merge(x,y);
}
int rank(int p,int v){
	int x=0,y=0,res;
	split(p,v-1,x,y);
	res=sz[x]+1;
	p=merge(x,y);
	return res; 
}
int kth(int p,int k){
	while(1){
		if(k<=sz[ch[p][0]])p=ch[p][0];
		else if(k==sz[ch[p][0]]+1)return p;
		else k-=sz[ch[p][0]]+1,p=ch[p][1];
	}
}
int pre(int &p,int v){
	int x=0,y=0,res;
	split(p,v-1,x,y);
	res=kth(x,sz[x]);
	p=merge(x,y);
	return res;
}
int nxt(int &p,int v){
	int x=0,y=0,res;
	split(p,v,x,y);
	res=kth(y,1);
	p=merge(x,y);
	return res;
}
int main(){
	srand(time(0));
	int op,x;
	n=rd();
	for(int i=1;i<=n;++i){
		op=rd(),x=rd();
		if(op==1)insert(rt,x);
		if(op==2)del(rt,x);
		if(op==3)printf("%d\n",rank(rt,x));
		if(op==4)printf("%d\n",val[kth(rt,x)]);
		if(op==5)printf("%d\n",val[pre(rt,x)]);
		if(op==6)printf("%d\n",val[nxt(rt,x)]);
	}

	return 0;
}

标签:总结,ch,val,int,treap,split,now,fhq
来源: https://www.cnblogs.com/We269/p/14983298.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有