FHQ-Treap学习笔记

FHQ-Treap学习笔记

Wogua_boy

感谢洛谷大佬远航之曲提供的学习资料~

FHQ-Treap是由清华大学的超级大佬范浩强发明的,一种实现简单的,可以支持所有Splay操作的的Treap树。

它只需要两个基础操作,就可以达到splay的所有功能。

split

它的主要思想就是把一个Treap分成两个。

split操作有两种类型,一种是按照权值分配,一种是按照前k个分配。

第一种就是把所有小于k的权值的节点分到一棵树中,第二种是把前k个分到一个树里。

对于我们遍历每一个点:

假如它的权值小于k,那么它的所有左子树,都要分到左边的树里,然后遍历它的右儿子。

假如它的权值大于k,那么它的所有右子树,都要分到右边的树里,然后遍历它的左儿子。

因为它的最多操作次数就是一直分到底,效率就是(O(logn))

merge

这个就是把两个Treap合成一个,保证第一个的权值小于第二个。

几个基本的平衡树操作

  1. insert

    插入一个权值为v的点,把树按照v的权值split成两个,再按照顺序merge回去。

  2. del

    删除权值为v的点,把树按照v分成两个a,b,再把a按照v-1分成c,d。

    把c的两个子儿子merge起来,再merge(merge(c,d),b)

  3. precursor

    找前驱,把root按v-1 split成x和y,在x里面找最大值。

  4. successor

    找后继,把root按v split成x和y,在y里面找最小值。

  5. rank

    把root按v-1 split成x和y,排名是x的size。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+100;
int ch[maxn][2];
int val[maxn];//本身权值 
int pri[maxn];//随机权值 
int sz[maxn];//子树大小 
int tot;
void up (int x) {
	sz[x]=1+sz[ch[x][0]]+sz[ch[x][1]];
}
int newNode (int v) {
	sz[++tot]=1;
	val[tot]=v;
	pri[tot]=rand();//可以改成自定义随机函数
	return tot; 
}
int merge (int x,int y) {
	if (!x||!y) return x+y;
	if (pri[x]<pri[y]) {
		ch[x][1]=merge(ch[x][1],y);
		up(x);
		return x;
	}
	else {
		ch[y][0]=merge(x,ch[y][0]);
		up(y);
		return y;
	}
}
void split (int u,int k,int &x,int &y) {
	if (!u) x=y=0;
	else {
		if (val[u]<=k) {
			x=u;
			split(ch[u][1],k,ch[u][1],y);
		}
		else {
			y=u;
			split(ch[u][0],k,x,ch[u][0]);
		}
		up(u);
	}
}
int kth (int u,int k) {
	while (1) {
		if (k<=sz[ch[u][0]]) {
			u=ch[u][0];
		}
		else if (k==sz[ch[u][0]]+1) {
			return u;
		}
		else {
			k-=sz[ch[u][0]]+1;
			u=ch[u][1];
		}
	}
}
int x,y,z,rt;
int main () {
	srand((unsigned)time(NULL));
	int _;
	scanf("%d",&_);
	while (_--) {
		int op,tt;
		scanf("%d%d",&op,&tt);
		if (op==1) {
            //插入x
			split(rt,tt,x,y);
			rt=merge(merge(x,newNode(tt)),y);
		}
		else if (op==2) {
            //删除x
			split(rt,tt,x,z);
			split(x,tt-1,x,y);
			y=merge(ch[y][0],ch[y][1]);
			rt=merge(merge(x,y),z);
		}
		else if (op==3) {
            //查询x的排名
			split(rt,tt-1,x,y);
			printf("%d
",sz[x]+1);
			rt=merge(x,y);
		}
		else if (op==4) {
            //查询排名x的数
			printf("%d
",val[kth(rt,tt)]);
		}
		else if (op==5) {
            //求x的前驱
			split(rt,tt-1,x,y);
			printf("%d
",val[kth(x,sz[x])]);
			rt=merge(x,y);
		}
		else {
            //求x的后继
			split(rt,tt,x,y);
			printf("%d
",val[kth(y,1)]);
			rt=merge(x,y);
		}
	}
}
原文地址:https://www.cnblogs.com/zhanglichen/p/14645666.html