您需要一种数据结构:
- 插入一个数\(x\)
- 删除一个数\(x\)
- 查询\(x\)这个数在所有数中的排名
- 查询排名为\(x\)的数
- 求\(x\)这个数的前驱(前驱定义为小于\(x\)的最大数)‘
- 求\(x\)这个数的后继(后继定义为大于\(x\)的最小数)
平衡树
- 不会
树状数组
- 不会
线段树
不会- 先离散化一下,因为数字太大了
- 线段树维护区间内有多少个数
- 离散化的新编号就是线段树对应区间的位置
插入ins()
- 计算\(x\)离散化后的对应编号\(num\)
- 单点修改区间\([num,num]\),+1即可
删除del()
- 计算\(x\)离散化后的对应编号\(num\)
- 单点修改区间\([num,num]\),-1即可
查询排名clac_rk()
- 计算\(x\)离散化后的对应编号\(num\)
- 查询区间\([1,num]\)的和,+1即是答案,因为\(x\)前面有若干个数,若干个数+1就\(x\)的排名
查询对应排名的数find_rk()
- 二分查找,判断\([1,mid]\)的和与给定排名的大小关系。
查前驱
find_rk(calc_rk(x)-1)
查后继
find_rk(calc_rk(x)+N+1)
,其中\(N\)为\(x\)的数量
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100005
#define lson (rt<<1)
#define rson (rt<<1|1)
int seg[MAXN<<2];
inline void pushup(int rt) {
seg[rt] = seg[lson] + seg[rson];
}
void update(int C,int L,int rt,int l,int r) {
if(l==r&&l==L) {
seg[rt] += C;
return;
}
int mid = (l+r)>>1;
if(L<=mid) update(C,L,lson,l,mid);
else update(C,L,rson,mid+1,r);
pushup(rt);
}
int query(int L,int R,int rt,int l,int r) {
if(L>R) return 0;
if(L<=l&&R>=r) return seg[rt];
if(L>r||R<l) return 0;
int mid = (l+r)>>1,ans = 0;
if(L<=mid) ans += query(L,R,lson,l,mid);
if(R>mid) ans += query(L,R,rson,mid+1,r);
return ans;
}
struct Discretization {
int temp[MAXN],num[MAXN],tot,cnt;
void reset() {
tot = 0;
cnt = 0;
}
int get_num(int u) {
int l = 1, r = tot;
while(l<r) {
int mid = (l+r+1)>>1;
if(num[mid]>u) r = mid - 1;
else l = mid;
}
return l;
}
int find(int rk) {
int l = 1,r = tot;
while(l<r) {
int mid = (l+r)>>1;
int x = query(1,mid,1,1,tot);
if(x>=rk) r = mid;
else l = mid + 1;
}
return num[l];
}
void add(int u) {
temp[++cnt] = u;
}
void unique() {
for(int i=1;i<=cnt;++i) {
if(temp[i]!=temp[i+1]) num[++tot] = temp[i];
}
}
}D;
struct Opt {
int opt,num;
}G[MAXN];
int N;
int main() {
D.reset();
scanf("%d",&N);
for(int i=1;i<=N;++i) {
scanf("%d%d",&G[i].opt,&G[i].num);
if(G[i].opt!=4) D.add(G[i].num);
}
std::sort(D.temp+1,D.temp+1+D.cnt);
D.unique();
std::memset(seg,0,sizeof(seg));
for(int i=1;i<=N;++i) {
if(G[i].opt==1) update(1,D.get_num(G[i].num),1,1,D.tot);
else if(G[i].opt==2) update(-1,D.get_num(G[i].num),1,1,D.tot);
else if(G[i].opt==3) printf("%d\n",query(1,D.get_num(G[i].num)-1,1,1,D.tot) + 1);
else if(G[i].opt==4) printf("%d\n",D.find(G[i].num));
else if(G[i].opt==5) {
int rk = query(1,D.get_num(G[i].num)-1,1,1,D.tot);
printf("%d\n",D.find(rk));
}
else if(G[i].opt==6) {
int x = D.get_num(G[i].num);
int rk = query(1,x-1,1,1,D.tot) + query(x,x,1,1,D.tot) + 1;
printf("%d\n",D.find(rk));
}
}
return 0;
}