Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
Input
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
Output
对于操作3,4,5,6每行输出一个数,表示对应答案
treap维护每个节点的数值和子树大小。
#include<cstdio> #include<cstdlib> #include<cstring> #define clr(a) memset(a,0,sizeof(a)) #define N 100001 int ch[N][2]; int sz[N],a[N]; int v[N]; int p=1,V; inline void preins(int x){ v[p]=V=x; sz[p]=1; a[p]=rand(); } inline void upd(int x){ if(x)sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; } struct bst{ int root; bst(){ root=0; } void insert(){ if(root)insert(root); else root=p++; } void insert(int&x){ bool d=V>v[x]; int&c=ch[x][d]; if(c)insert(c); else c=p++; if(a[ch[x][d]]>a[x])rot(x,d); upd(x); }void rot(int&w,int c){ int u=ch[w][c]; ch[w][c]=ch[u][c^1]; ch[u][c^1]=w; upd(w); w=u; upd(u); } int lss(int x){ int w=root,ans=0; while(w){ if(v[w]<x)ans+=sz[ch[w][0]]+1; w=ch[w][v[w]<x]; } return ans; } void del(int&w,int V){ if(!w)return; if(v[w]==V)del(w); else del(ch[w][v[w]<V],V); upd(w); } void del(int&w){ if(ch[w][0]|ch[w][1]){ bool d=a[ch[w][0]]<a[ch[w][1]]; int u=ch[w][d]; rot(w,d); del(ch[w][d^1]); upd(u); }else w=0; } int prv(int x){ int w=root,a=-1; while(w){ if(x>v[w])a=v[w]; w=ch[w][x>v[w]]; } return a; } int nxt(int x){ int w=root,a=-1; while(w){ if(x<v[w])a=v[w]; w=ch[w][x>=v[w]]; } return a; } int rnkx(int x){ int w=root,a=sz[ch[w][0]]+1; while(a^x){ if(x<a)w=ch[w][0],a-=sz[ch[w][1]]+1; else w=ch[w][1],a+=sz[ch[w][0]]+1; } return v[w]; } }; bst b; int n,p1,p2; int main(){ freopen("in.txt","r",stdin); freopen("o.txt","w",stdout); clr(ch);clr(sz);clr(a);clr(v); a[0]=-1; scanf("%d",&n); while(n--){ scanf("%d%d",&p1,&p2); switch(p1){ case 1:preins(p2);b.insert();break; case 2:b.del(b.root,p2);break; case 3:printf("%d\n",b.lss(p2)+1);break; case 4:printf("%d\n",b.rnkx(p2));break; case 5:printf("%d\n",b.prv(p2));break; case 6:printf("%d\n",b.nxt(p2));break; } } return 0; }
时间: 2024-10-13 06:08:23