【题意】您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
【分析】完全没必要用平衡树,可以用离线+离散线段树,或者在线的动态内存线段树都可以。
对于操作3就是查询<=x-1的数的个数,再加+1就是x的排名
对于操作4,直接线段树上二分第k大
对于操作5,查询<=x-1的个数sum,则查找第sum大的数便是前驱
对于操作6,查询<=x的个数sum,则查找第sum+1大的数就是后继
【AC CODE(离线线段树)】384ms
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = (1e5)+10;
struct NODE{
int op,x;
}in[MAXN];
int a[MAXN],num[MAXN],n;
int sum[MAXN<<1];
inline int id(int x, int y){return x+y|x!=y;}
void update(int x, int y, int p, int v)
{
if(x == y)
{
sum[id(x,y)] += v;
return;
}
int m = (x+y)>>1;
if(p <= m) update(x,m,p,v);
else update(m+1,y,p,v);
sum[id(x,y)] = sum[id(x,m)]+sum[id(m+1,y)];
}
void find_rk(int x, int y, int v, int &ans)
{
if(x == y)
{
ans += sum[id(x,y)];
return;
}
int m = (x+y)>>1;
if(v <= m) find_rk(x,m,v,ans);
else
{
ans += sum[id(x,m)];
find_rk(m+1,y,v,ans);
}
}
int find_k(int x, int y, int k)
{
if(x == y) return x;
int m = (x+y)>>1, d = sum[id(x,m)];
if(k <= d) return find_k(x,m,k);
return find_k(m+1,y,k-d);
}
inline int mhash(int v){return lower_bound(num,num+n,v)-num;}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int q,cnt = 0;
scanf("%d", &q);
rep(i,0,q)
{
scanf("%d%d", &in[i].op, &in[i].x);
if(4 != in[i].op)
num[cnt++] = in[i].x;
}
num[cnt++] = -INF;num[cnt++] = INF;
sort(num,num+cnt);
n = unique(num,num+cnt)-num;
rep(i,0,q)
{
if(1 == in[i].op) update(0,n-1,mhash(in[i].x),1);
else if(2 == in[i].op) update(0,n-1,mhash(in[i].x),-1);
else if(3 == in[i].op)
{
int ans = 0;
find_rk(0,n-1,mhash(in[i].x)-1,ans);
printf("%d\n", ans+1);
}
else if(4 == in[i].op) printf("%d\n", num[find_k(0,n-1,in[i].x)]);
else if(5 == in[i].op)
{
int ans = 0;
find_rk(0,n-1,mhash(in[i].x)-1,ans);
printf("%d\n", num[find_k(0,n-1,ans)]);
}
else
{
int ans = 0;
find_rk(0,n-1,mhash(in[i].x),ans);
printf("%d\n", num[find_k(0,n-1,ans+1)]);
}
}
return 0;
}
【AC CODE(在线动态内存线段树)】568ms
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = (1e5)+10,MAXM = MAXN*20+10;
int a[MAXN],n;
int sum[MAXM],lc[MAXM],rc[MAXM],tol;
inline void newnode(int &u, int x, int y)
{
u = ++tol;
lc[u] = 0;rc[u] = 0;
}
void update(int &u, int x, int y, int p, int v)
{
if(!u) newnode(u,x,y);
if(x == y)
{
sum[u] += v;
return;
}
int m = (x+y)>>1;
if(p <= m) update(lc[u],x,m,p,v);
else update(rc[u],m+1,y,p,v);
sum[u] = sum[lc[u]]+sum[rc[u]];
}
void find_rk(int &u, int x, int y, int v, int &ans)
{
if(!u) newnode(u,x,y);
if(x == y)
{
ans += sum[u];
return;
}
int m = (x+y)>>1;
if(v <= m) find_rk(lc[u],x,m,v,ans);
else
{
ans += sum[lc[u]];
find_rk(rc[u],m+1,y,v,ans);
}
}
int find_k(int u, int x, int y, int k)
{
if(!u) newnode(u,x,y);
if(x == y) return x-10000000;
int m = (x+y)>>1, d = sum[lc[u]];
if(k <= d) return find_k(lc[u],x,m,k);
return find_k(rc[u],m+1,y,k-d);
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
int q,cnt = 0,n = 10000000*2;
scanf("%d", &q);
int rt;
newnode(rt,0,n);
rep(i,0,q)
{
int op,x;
scanf("%d%d", &op,&x);
if(4 != op)
x += 10000000;
if(1 == op) update(rt,0,n,x,1);
else if(2 == op) update(rt,0,n,x,-1);
else if(3 == op)
{
int ans = 0;
find_rk(rt,0,n,x-1,ans);
printf("%d\n", ans+1);
}
else if(4 == op) printf("%d\n", find_k(rt,0,n,x));
else if(5 == op)
{
int ans = 0;
find_rk(rt,0,n,x-1,ans);
printf("%d\n",find_k(rt,0,n,ans));
}
else
{
int ans = 0;
find_rk(rt,0,n,x,ans);
printf("%d\n", find_k(rt,0,n,ans+1));
}
}
return 0;
}