1568:普通平衡树

本文介绍了一种数据结构,用于维护一组数,支持插入、删除操作,以及查询指定数的排名、对应的数、前趋和后继。使用了二叉搜索树作为基础,实现了高效查询和更新功能。
摘要由CSDN通过智能技术生成

【题目描述】

这是一道模板题。

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

1、插入 x� 数;

2、删除 x� 数(若有多个相同的数,因只删除一个);

3、查询 x� 数的排名(若有多个相同的数,因输出最小的排名);

4、查询排名为 x� 的数;

5、求 x� 的前趋(前趋定义为小于 x�,且最大的数);

6、求 x� 的后继(后继定义为大于 x�,且最小的数)。

【输入】

第一行为 n�,表示操作的个数,下面 n� 行每行有两个数 opt��� 和 x�,opt��� 表示操作的序号( 1≤opt≤61≤���≤6)。

【输出】

对于操作 3、4、5、63、4、5、6 每行输出一个数,表示对应答案。

【输入样例】

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

【输出样例】

106465
84185
492737

【样例代码】

#include<bits/stdc++.h>
using namespace std;
struct S{
	int lc,rc,vis,pos,cnt,sze;
}t[500005];int n,m,cnt=0,rt=0;
void zig(int &k){
	int y=t[k].lc;
	t[k].lc=t[y].rc;
	t[y].rc=k;
	t[y].sze=t[k].sze;
	t[k].sze=t[t[k].lc].sze+t[t[k].rc].sze+t[k].cnt;
	k=y;
}
void zag(int &k){
	int y=t[k].rc;
	t[k].rc=t[y].lc;
	t[y].lc=k;
	t[y].sze=t[k].sze;
	t[k].sze=t[t[k].lc].sze+t[t[k].rc].sze+t[k].cnt;
	k=y;
}
void inse(int &k,int key){
	if(!k){
		k=++cnt;t[k].vis=key;t[k].pos=rand();
		t[k].cnt=t[k].sze=1;t[k].lc=t[k].rc=0;
		return ;
	}
	else ++t[k].sze;
	if(t[k].vis==key)++t[k].cnt;
	else if(key<t[k].vis){
		inse(t[k].lc,key);
		if(t[t[k].lc].pos<t[k].pos)zig(k);
	}
	else {
		inse(t[k].rc,key);
		if(t[t[k].rc].pos<t[k].pos)zag(k);
	}
	return ;
}
void del(int &k,int key){
	if(t[k].vis==key){
		if(t[k].cnt>1)--t[k].cnt,--t[k].sze;
		else if(!t[k].lc || !t[k].rc)k=t[k].lc+t[k].rc;
		else if(t[t[k].lc].pos<t[t[k].rc].pos)zig(k),del(k,key);
		else zag(k),del(k,key);
		return ;
	}
	--t[k].sze;
	if(key<t[k].vis)del(t[k].lc,key);
	else del(t[k].rc,key);
}
int quepre(int key){
	int k=rt,res=-0x3f3f3f3f;
	while(k){
		if(t[k].vis<key)res=t[k].vis,k=t[k].rc;
		else k=t[k].lc;
	}
	return res;
}
int quenex(int key){
	int k=rt,nex=0x3f3f3f3f;
	while(k){
		if(t[k].vis>key)nex=t[k].vis,k=t[k].lc;
		else k=t[k].rc;
	}
	return nex;
}
int quekth(int k){
	int x=rt;
	while(x){
		if(t[t[x].lc].sze<k && t[t[x].lc].sze+t[x].cnt>=k)return t[x].vis;
		if(t[t[x].lc].sze>=k)x=t[x].lc;
		else k-=t[t[x].lc].sze+t[x].cnt,x=t[x].rc;
	}
	return 0;
}
int querank(int key){
	int x=rt,res=0;
	while(x){
		if(key==t[x].vis)return res+t[t[x].lc].sze+1;
		if(key<t[x].vis)x=t[x].lc;
		else res+=t[t[x].lc].sze+t[x].cnt,x=t[x].rc;
	}
	return res;
}
int main(){
	int n;
	int op,x;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&op,&x);
		if(op==1)inse(rt,x);
		if(op==2)del(rt,x);
		if(op==3)printf("%d\n",querank(x));
		if(op==4)printf("%d\n",quekth(x));
		if(op==5)printf("%d\n",quepre(x));
		if(op==6)printf("%d\n",quenex(x));
	}
	
	return 0;
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值