treap
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:插入x数,删除x数(若有多个相同的数,因只删除一个),查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名),查询排名为x的数,求x的前驱(前驱定义为小于x,且最大的数),求x的后继(后继定义为大于x,且最小的数)。
treap似乎就是一个保持堆性质的二叉搜索树。结点的优先级是随机分配的。可以保证treap的所有操作,期望时间复杂度都为logn。
#include <ctime>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn=1e5+5, INF=1e9;
int randint(){ //比手写rand效果好
return rand();
}
void get(int &x){
static int flag; static char c; flag=1; //static的变量只初始化一次
for (c=getchar(); !isdigit(c); c=getchar())
if (c=='-') flag=-1;
for (x=c-48; c=getchar(), isdigit(c); )
x=(x<<3)+(x<<1)+c-48; x*=flag;
}
struct Treap{
//时刻牢记旋转操作不破坏bst的性质
//小根堆 x:结点编号
//空间复杂度:插入次数
//v:结点的值 w:结点的优先级
int tot, root, siz[maxn], v[maxn], w[maxn], s[maxn][2];
void up(int x){ siz[x]=siz[s[x][0]]+siz[s[x][1]]+1; }
void spin(int &x, int p){ //把p所指的孩子旋转上来
int t=s[x][p];
s[x][p]=s[t][!p]; s[t][!p]=x; //重构关系
up(x); up(t); x=t; //维护子树大小 将当前位置更换
}
void ins(int &x, int c){ //不停把优先级小的转上来
if (!x){ x=++tot; siz[x]=1;
v[x]=c; w[x]=randint(); return; }
++siz[x];
if (c<=v[x]){ ins(s[x][0], c); //左边是v小于等于v[x]的结点
if (w[s[x][0]]<w[x]) spin(x, 0); }
else { ins(s[x][1], c);
if (w[s[x][1]]<w[x]) spin(x, 1); }
}
void del(int &x, int c){ //把这个数一直转到叶子节点然后删除
if (v[x]==c){
if (!s[x][0]||!s[x][1]){
x=s[x][0]+s[x][1]; return; }
if (w[s[x][0]]>w[s[x][1]]){
spin(x, 1); del(s[x][0], c); }
else{ spin(x, 0); del(s[x][1], c); }
} //别忘记这里也要update!
else if (v[x]>c) del(s[x][0], c);
else del(s[x][1], c);
up(x); //由于没有旋转操作需要手动维护
}
int ask_id(int x, int c){ //询问c的最小排名
if (!x) return 1;
if (c<=v[x]) return ask_id(s[x][0], c);
else return ask_id(s[x][1], c)+siz[s[x][0]]+1;
}
int ask_num(int x, int c){ //询问第c个数
if (siz[s[x][0]]==c-1) return v[x];
if (siz[s[x][0]]>=c) return ask_num(s[x][0], c);
else return ask_num(s[x][1], c-siz[s[x][0]]-1);
}
int pre(int x, int c){ //询问小于c且最大的数
if (!x) return -INF;
if (v[x]<c) return max(v[x], pre(s[x][1], c)); //答案有可能是根
else return pre(s[x][0], c);
}
int nxt(int x, int c){ //询问大于c且最小的数
if (!x) return INF;
if (v[x]>c) return min(v[x], nxt(s[x][0], c)); //答案有可能是根
else return nxt(s[x][1], c);
}
}treap;
int n, op, x;
int main(){
get(n); srand(time(NULL));
for (int i=0; i<n; ++i){
get(op); get(x);
if (op==1) treap.ins(treap.root, x);
if (op==2) treap.del(treap.root, x);
if (op==3) printf("%d\n", treap.ask_id(treap.root, x));
if (op==4) printf("%d\n", treap.ask_num(treap.root, x));
if (op==5) printf("%d\n", treap.pre(treap.root, x));
if (op==6) printf("%d\n", treap.nxt(treap.root, x));
}
return 0;
}