FHQ-Treap 树 ← 洛谷P3369、AcWing253

【题目来源】
https://www.luogu.com.cn/problem/P3369
https://www.acwing.com/problem/content/255/

【题目描述】
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入数值 x。
2. 删除数值 x(若有多个相同的数,应只删除一个)。
3. 查询数值 x 的排名(若有多个相同的数,应输出最小的排名)。
4. 查询排名为 x 的数值。
5. 求数值 x 的前驱(前驱定义为小于 x 的最大的数)。
6. 求数值 x 的后继(后继定义为大于 x 的最小的数)。
注意: 数据保证查询的结果一定存在。

【输入格式】
第一行为 n,表示操作的个数。
接下来 n 行每行有两个数 opt 和 x,opt 表示操作的序号(1≤opt≤6)。

【输出格式】
对于操作 3,4,5,6 每行输出一个数,表示对应答案。

【数据范围】
1≤n≤100000,所有数均在 −10^7 到 10^7 内。

【输入样例】
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

【输出样例】
106465
84185
492737


【算法分析】
● FHQ−Treap,也称非旋 Treap,由范浩强提出。顾名思义,FHQ−Treap 就是不需要通过旋转,而是通过分裂(split)与合并(merge)维护的 Treap。FHQ−Treap 与 Treap 的另外一个区别是 FHQ−Treap 可持久化。
● FHQ-Treap 的高明之处在于所有的操作都
只用到了分裂(split)与合并(merge)这两个基本操作。
● 本题的
Treap 树实现参见:https://blog.csdn.net/hnjzsyjyj/article/details/138482439
● 本题的替罪羊树实现参见:https://blog.csdn.net/hnjzsyjyj/article/details/128647972

【算法代码】

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

const int maxn=500005;
int ch[maxn][2],val[maxn],pri[maxn],cnt[maxn],id;

int read() { //fast read
	int x=0,f=1;
	char c=getchar();
	while(c<'0' || c>'9') { //!isdigit(c)
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0' && c<='9') { //isdigit(c)
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}

void update(int x) {
	cnt[x]=1+cnt[ch[x][0]]+cnt[ch[x][1]];
}

int new_node(int v) {
	cnt[++id]=1;
	val[id]=v;
	pri[id]=rand();
	return id;
}

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);
		update(x);
		return x;
	} else {
		ch[y][0]=merge(x,ch[y][0]);
		update(y);
		return y;
	}
}

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

int kth(int cur,int k) {
	while(1) {
		if (k<=cnt[ch[cur][0]])
			cur=ch[cur][0];
		else if (k==cnt[ch[cur][0]]+1)
			return cur;
		else
			k-=cnt[ch[cur][0]]+1,cur=ch[cur][1];
	}
}

int main() {
	int T,opt,x,y,z,a,b,root=0;
	T=read();
	while(T--) {
		opt=read(),a=read();
		if (opt==1) {
			split(root,a,x,y);
			root=merge(merge(x,new_node(a)),y);
		} else if (opt==2) {
			split(root,a,x,z);
			split(x,a-1,x,y);
			y=merge(ch[y][0],ch[y][1]);
			root=merge(merge(x,y),z);
		} else if (opt==3) {
			split(root,a-1,x,y);
			printf("%d\n",cnt[x]+1);
			root=merge(x,y);
		} else if (opt==4)
			printf("%d\n",val[kth(root,a)]);
		else if (opt==5) {
			split(root,a-1,x,y);
			printf("%d\n",val[kth(x,cnt[x])]);
			root=merge(x,y);
		} else {
			split(root,a,x,y);
			printf("%d\n",val[kth(y,1)]);
			root=merge(x,y);
		}
	}

	return 0;
}


/*
in:
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

out:
106465
84185
492737
*/



【参考文献】
https://www.luogu.com.cn/blog/85514/fhq-treap-xue-xi-bi-ji
https://blog.csdn.net/m0_51796369/article/details/119834710
http://www.yhzq-blog.cc/fhq-treap%E6%80%BB%E7%BB%93/
https://www.luogu.com.cn/problem/P3369
https://www.acwing.com/problem/content/255/
https://www.acwing.com/blog/content/4455/
https://www.acwing.com/problem/content/description/268/
https://blog.csdn.net/weixin_44316314/article/details/114155492




 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值