FHQtreap笔记

参考https://msd.misuland.com/pd/4425384081022256588

侵删。

变量

struct node  {
	int ls, //左儿子下标
	rs, //右儿子下标
	r, //随机权值
	v, //权值
	size; //树的大小
} tree[maxn];

int tot = 0;

新增节点

int New(int val)  {
	tree[++tot].v = val;
	tree[tot].r = rand();
	tree[tot].size=1;
	return tot;
}

节点size更新

void upd(int x) {
	tree[x].size = tree[tree[x].ls].size + tree[tree[x].rs].size + 1;
}

merge (合并)

  

//将以x,y为根的两棵树合并为一棵,并返回合并后的根节点编号。
//以x为根的树中所有任意的权值不大于以y为根的树中所有任意的权值。
//令r满足小根堆性质
int merge(int x, int y) {
	if(!x || !y)  return x | y;
	if(tree[x].r < tree[y].r) {
		tree[x].rs = merge(tree[x].rs, y); //把y插入到x右子树
		upd(x);
		return x;
	}
	else {
		tree[y].ls = merge(x, tree[y].ls); //把x插入到y左子树
		upd(y);
		return y;
	}
}

split (分离)

//将以p为根的树分裂为两棵树,根分别是x和y。
//其中x树中所有节点的权值小于等于val,y树中所有节点的权值大于val。
void split(int p, int val, int &x, int &y)  {
	if(!p) {
		x = y = 0;
		return;
	}
	if(tree[p].v <= val) {
		x = p;
		split(tree[p].rs, val, tree[p].rs, y); //右子树 小于val的节点留下来,大于val的传到y
	}
	else {
		y = p;
		split(tree[p].ls, val, x, tree[p].ls); //左子树 大于val的节点留下来,小于val的传到x
	}
}

插入

分裂为小于等于val-1大于等于val两棵子树x、y,然后New一个节点z值为val,依次合并x,y,z。

删除

两次split分裂成三棵子树分别是x,y,z,x<val,y=val,z>val。
如果只删除一个val,把y变为其两棵子树的合并,然后依次合并x,y,z。
如果全部删除,直接合并x,z。

posted @ 2020-08-07 13:51  __ZRH  阅读(185)  评论(0)    收藏  举报