题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入xxx数
- 删除xxx数(若有多个相同的数,因只删除一个)
- 查询xxx数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
- 查询排名为xxx的数
- 求xxx的前驱(前驱定义为小于xxx,且最大的数)
- 求xxx的后继(后继定义为大于xxx,且最小的数)
输入输出格式
输入格式:
第一行为nnn,表示操作的个数,下面nnn行每行有两个数optoptopt和xxx,optoptopt表示操作的序号( 1≤opt≤6 1 \leq opt \leq 6 1≤opt≤6 )
输出格式:
对于操作3,4,5,63,4,5,63,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,128M
1.n的数据范围: n≤100000 n \leq 100000 n≤100000
2.每个数的数据范围: [−107,107][-{10}^7, {10}^7][−107,107]
来源:Tyvj1728 原名:普通平衡树
思路:
用权值线段树写,注意要先离散化
(3)求x的排名,就是求[1,x-1]的区间sum值+1
(5)求x的前驱,就是sum(1,x-1)求出1到x-1的所有数的个数,再求排名为sum(1,x-1)的数
(6)求x的后继,就是sum(1,x)求出1到x的所有数的个数,再求排名为sum(1,x)+1的数
坑点:
(1)题目中会问你一个从来没插入的数的前驱/后继,所以存数的时候都要先存下来,再离散化
(2)问你数x的排名时,可能数x是最小的那个数,那么就不能sum(1,x-1)了,因为x对应的值是1,sum(1,0)(左端点大于有端点)会导致MLE,特判一下当x是最小的数时,输出1就可
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=100005;
int num[N];
struct A{
int opt,x;
}q[N];
int tree[N<<2];
void push_up(int rt){
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void update(int p,int c,int l,int r,int rt){
if(l==r){
tree[rt]+=c;
return ;
}
int m=(l+r)>>1;
if(p<=m)update(p,c,lson);
else update(p,c,rson);
push_up(rt);
}
int query1(int L,int R,int l,int r,int rt){//区间求和
if(L<=l&&R>=r){
return tree[rt];
}
int m=(l+r)>>1;
int ans=0;
if(L<=m)ans+=query1(L,R,lson);
if(R>m)ans+=query1(L,R,rson);
return ans;
}
int query2(int k,int l,int r,int rt){//查询排名为k的数
if(l==r){
return l;
}
int m=(l+r)>>1;
if(k<=tree[rt<<1])return query2(k,lson);
else return query2(k-tree[rt<<1],rson);
}
int main(){
int m,k=0;
scanf("%d",&m);
for(int i=0;i<m;i++){
scanf("%d%d",&q[i].opt,&q[i].x);
if(q[i].opt!=4)num[k++]=q[i].x;
}
sort(num,num+k);
int n=unique(num,num+k)-num;
for(int i=0;i<m;i++){
int x=lower_bound(num,num+n,q[i].x)-num+1;
if(q[i].opt==1){//插入
update(x,1,1,n,1);
}
if(q[i].opt==2){//删除
update(x,-1,1,n,1);
}
if(q[i].opt==3){//查询x的排名
if(x-1==0)printf("1\n");
else printf("%d\n",query1(1,x-1,1,n,1)+1);
}
if(q[i].opt==4){//查询排名为x的数
printf("%d\n",num[query2(q[i].x,1,n,1)-1]);
}
if(q[i].opt==5){//求小于x的最大的数的值
int rk=query1(1,x-1,1,n,1);
printf("%d\n",num[query2(rk,1,n,1)-1]);
}
if(q[i].opt==6){//求大于x的最小的数的值
int sum=query1(1,x,1,n,1);
printf("%d\n",num[query2(sum+1,1,n,1)-1]);
}
}
}