#107. 维护全序集
题目描述
这是一道模板题,其数据比「普通平衡树」更强。
如未特别说明,以下所有数据均为整数。
维护一个多重集 S SS ,初始为空,有以下几种操作:
- 把 x xx 加入 S SS
- 删除 S SS 中的一个 x xx,保证删除的 x xx 一定存在
- 求 S SS 中第 k kk 小
- 求 S SS 中有多少个元素小于 x xx
- 求 S SS 中小于 x xx 的最大数
- 求 S SS 中大于 x xx 的最小数
操作共 n nn 次。
输入格式
第一行一个整数 n nn,表示共有 n nn 次操作 。
接下来 n nn 行,每行为以下几种格式之一 :
0 x
,把 x xx 加入 S SS1 x
,删除 S SS 中的一个 x xx,保证删除的数在 S SS 中一定存在2 k
,求 S SS 中第 k kk 小的数,保证要求的数在 S SS 中一定存在3 x
,求 S SS 中有多少个数小于 x xx4 x
,求 S SS 中小于 x xx 的最大数,如果不存在,输出 −1 -1−15 x
,求 S SS 中大于 x xx 的最小数,如果不存在,输出 −1 -1−1
输出格式
对于每次询问,输出单独一行表示答案。
样例
样例输入
5
0 3
0 4
2 2
1 4
3 3
样例输出
4
0
数据范围与提示
1≤n≤3×105,0≤x≤109 1 leq n leq 3 imes 10 ^ 5, 0 leq x leq 10 ^ 91≤n≤3×105,0≤x≤109
#include<iostream> #include<cstdio> #include<cstring> #define INF 0x7fffffff #define maxn 400010 using namespace std; int m,rt,son[maxn][2],fa[maxn],val[maxn],cnt[maxn],sz[maxn],size; void update(int x){ sz[x]=sz[son[x][1]]+sz[son[x][0]]+cnt[x]; } void rotate(int x,int &k){ int y=fa[x],z=fa[fa[x]],l,r; if(son[y][0]==x)l=0;else l=1;r=l^1; if(y==k)k=x; else son[z][son[z][1]==y]=x; fa[x]=z;fa[y]=x;fa[son[x][r]]=y; son[y][l]=son[x][r];son[x][r]=y; update(y);update(x); } void splay(int x,int &k){ while(x!=k){ int y=fa[x],z=fa[fa[x]]; if(y!=k){ if((son[z][0]==y)^(son[y][0]==x))rotate(x,k); else rotate(y,k); } rotate(x,k); } } void Insert(int v){ int y=0,k=rt; while(k&&val[k]!=v)y=k,k=son[k][v>val[k]]; if(k)cnt[k]++; else { k=++size; cnt[k]=sz[k]=1; fa[k]=y;val[k]=v; if(y)son[y][v>val[y]]=k; } splay(k,rt); } int find2(int x){ x++;int k=rt; if(sz[k]<x)return 0; while(1){ if(sz[son[k][0]]<x&&sz[son[k][0]]+cnt[k]>=x)return k; if(sz[son[k][0]]>=x)k=son[k][0]; else x-=sz[son[k][0]]+cnt[k],k=son[k][1]; } return k; } void find1(int x){ int k=rt;if(!k)return; while(son[k][x>val[k]]&&val[k]!=x) k=son[k][x>val[k]]; splay(k,rt); } int nxt(int x,int f){ find1(x);//if(!rt)return 0; if((val[rt]>x&&f)||(val[rt]<x&&!f))return rt; int k=son[rt][f]; while(son[k][f^1])k=son[k][f^1]; return k; } void del(int v){ find1(v); int x=rt,k; if(cnt[rt]>1){cnt[rt]--;sz[rt]--;return;} if(son[rt][0]*son[rt][1]==0){ rt=son[rt][0]+son[rt][1]; } else { k=son[rt][1]; while(son[k][0])k=son[k][0];sz[k]+=sz[son[x][0]]; fa[son[x][0]]=k; son[k][0]=son[x][0];rt=son[x][1]; } fa[rt]=0;splay(k,rt); } void debug(){ printf("%d ",val[rt]); } int main(){ scanf("%d",&m); Insert(0x7fffffff);Insert(-0x7fffffff); int op,x; while(m--){ scanf("%d%d",&op,&x); if(op==0)Insert(x); if(op==1)del(x); if(op==2)printf("%d ",val[find2(x)]); if(op==3){ find1(x); int ans=sz[son[rt][0]]-1; if(val[rt]<x)ans+=cnt[rt]; printf("%d ",ans); } if(op==4){ int w=val[nxt(x,0)]; if(w==INF||w==-INF)puts("-1"); else printf("%d ",w); } if(op==5){ int w=val[nxt(x,1)]; if(w==INF||w==-INF)puts("-1"); else printf("%d ",w); } } return 0; }