#A. 普通平衡树

本文介绍了一种基于二叉堆的数据结构,用于支持高效的插入、删除、查询排名、查找特定值的前驱和后继等操作,适用于需要快速处理大量重复数值的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

输入格式

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

输出格式

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

样例

输入数据 1

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

输出数据 1

106465
84185
492737

提示

  • 传统题  1000ms   256MiB
  • 说明

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

  • 插入 x 数;
  • 删除 x 数(若有多个相同的数,应只删除一个);
  • 查询 x 数的排名(若有多个相同的数,因输出最小的排名);
  • 查询排名为 x 的数;
  • 求 x 的前驱(前驱定义为小于 x,且最大的数);
  • 求 x 的后继(后继定义为大于 x,且最小的数)。
  • 数据范围:1≤n≤10^{5},−≤x≤107
  • #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)cout<<querank(x)<<endl;
    		if(op==4)cout<<quekth(x)<<endl;
    		if(op==5)cout<<quepre(x)<<endl;
    		if(op==6)cout<<quenex(x)<<endl;
    	}
    	
    	return 0;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值