【数据结构】fhq_treap

使用 fhq_treap 竟然让我一发就过了这题,nice,比之前编写 Splay 的时候对着 y总 代码 debug 的体验好多了。经此一役,不得不承认 fhq_treap 真的非常容易编写而且错误率低,不仅如此,它所能支持的操作也可以覆盖 Splay 所支持的,而且能避免很多复杂的边界问题,绝赞。

关于 fhq_treap,它和 Splay 同样具有两个核心操作,不过 Splay 的核心操作是 \(splay\)\(rotate\),而 fhq_treap 的核心操作是 \(merge\)\(split\)​。

可以说是理解 \(merge\)\(split\) 之后 fhq_treap 就基本解决了。

下面简单介绍 \(merge\)\(split\)

\(split\) 分裂

通过传入一个值 \(val\),利用这个 \(val\) 将传入的根节点 \(root\) 所在子树分割成两棵树,并将这两树的根节点编号记下来。

图解:
一开始树的结构:
image

当传入的值 \(val=25\) 时,分裂出的两棵树:
image

结合代码实现理解:

void split(int u, int val, int &x, int &y){
	if(!u) return x=y=0, void(); // 当走到空节点的时候返回。
	if(tr[u].v<=val)
		x=u, split(rs, val, rs, y); // 向右子树分裂
	else
		y=u, split(ls, val, x, ls); // 向左子树分裂
	pushup(u);
}

\(merge\) 合并

合并根节点编号为 \(x\)\(y\) 的两个子树并返回新树的根节点编号。

int merge(int x, int y){
	if(!x || !y) return x+y; // 如果有一个是空节点,返回另一个节点编号。
	if(tr[x].key>tr[y].key){ // 按照优先级来决定哪个作为根节点。
		tr[x].r=merge(tr[x].r, y);
		pushup(x);
		return x;
	}
	else{
		tr[y].l=merge(x, tr[y].l);
		pushup(y);
		return y;
	}
}

全部代码:

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5;

struct Node{
	int l, r;
	int key;
	int sz, v;
	
	#define ls tr[u].l
	#define rs tr[u].r
}tr[N];

int root, idx;

void pushup(int u){
	tr[u].sz=tr[ls].sz+tr[rs].sz+1;
}

int add(int v){
	++idx;
	tr[idx].key=rand(), tr[idx].sz=1, tr[idx].v=v;
	return idx;
}

int merge(int x, int y){
	if(!x || !y) return x+y;
	if(tr[x].key>tr[y].key){
		tr[x].r=merge(tr[x].r, y);
		pushup(x);
		return x;
	}
	else{
		tr[y].l=merge(x, tr[y].l);
		pushup(y);
		return y;
	}
}

void split(int u, int val, int &x, int &y){
	if(!u) return x=y=0, void();
	if(tr[u].v<=val)
		x=u, split(rs, val, rs, y);
	else
		y=u, split(ls, val, x, ls);
	pushup(u);
}

void insert(int v){
	int x, y;
	split(root, v, x, y);
	root=merge(x, merge(add(v), y));
}

void remove(int v){
	int x, y, z;
	split(root, v, x, z);
	split(x, v-1, x, y);
	y=merge(tr[y].l, tr[y].r);
	root=merge(merge(x, y), z);
}

int val4rk(int v){
	int x, y;
	split(root, v-1, x, y);
	int res=tr[x].sz+1;
	root=merge(x, y);
	return res;
}

int rk4val(int k){
	int u=root;
	while(u){
		if(tr[ls].sz+1==k) return tr[u].v;
		else if(tr[ls].sz>=k) u=ls;
		else k-=tr[ls].sz+1, u=rs;
	}
	return -1;
}

int get_prev(int v){
	int x, y;
	split(root, v-1, x, y);
	int u=x;
	while(rs) u=rs;
	int res=tr[u].v;
	root=merge(x, y);
	return res;
}



int get_next(int v){
	int x, y;
	split(root, v, x, y);
	int u=y;
	while(ls) u=ls;
	int res=tr[u].v;
	root=merge(x, y);
	return res;
}

int main(){
	ios::sync_with_stdio(false);
	srand(131);
	int q; cin>>q;
	while(q--){
		int op, x; cin>>op>>x;
		if(op==1) insert(x);
		else if(op==2) remove(x);
		else if(op==3) cout<<val4rk(x)<<endl;
		else if(op==4) cout<<rk4val(x)<<endl;
		else if(op==5) cout<<get_prev(x)<<endl;
		else if(op==6) cout<<get_next(x)<<endl;
	}
	return 0;
}
posted @ 2021-09-27 22:28  HinanawiTenshi  阅读(61)  评论(0编辑  收藏  举报