版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38083668/article/details/82932211
题目描述
这是一道模板题,其数据比「普通平衡树」更强。
如未特别说明,以下所有数据均为整数。
维护一个多重集 S S S ,初始为空,有以下几种操作:
- 把 x x x 加入 S S S
- 删除 S S S 中的一个 x x x,保证删除的 x x x 一定存在
- 求 S S S 中第 k k k 小
- 求 S S S 中有多少个元素小于 x x x
- 求 S S S 中小于 x x x 的最大数
- 求 S S S 中大于 x x x 的最小数
操作共 n n n 次。
输入格式
第一行一个整数 n n n,表示共有 n n n 次操作 。
接下来 n n n 行,每行为以下几种格式之一 :
0 x
,把 x x x 加入 S S S1 x
,删除 S S S 中的一个 x x x,保证删除的数在 S S S 中一定存在2 k
,求 S S S 中第 k k k 小的数,保证要求的数在 S S S 中一定存在3 x
,求 S S S 中有多少个数小于 x x x4 x
,求 S S S 中小于 x x x 的最大数,如果不存在,输出 −1 -1 −15 x
,求 S S S 中大于 x x x 的最小数,如果不存在,输出 −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 \times 10 ^ 5, 0 \leq x \leq 10 ^ 9 1≤n≤3×105,0≤x≤109
代码(旋转Treap):
#include <bits/stdc++.h>
using namespace std;
const int inf=1e9+7;
const int Max=300005;
int n,m,tot,root=1,ans;
struct shu{int l,r,data,num,size,cnt;};
shu a[Max];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c=getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void print(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) print(x/10);
putchar('0'+x%10);
}
inline int NEW(int x)
{
a[++tot].num=x;
a[tot].size=a[tot].cnt=1;
a[tot].data=rand();
return tot;
}
inline void update(int p)
{
a[p].size=a[a[p].l].size+a[a[p].r].size+a[p].cnt;
}
inline void build()
{
NEW(-inf),NEW(inf);
a[1].r=2;
update(root);
}
inline void zig(int &p)
{
int q=a[p].l;
a[p].l=a[q].r,a[q].r=p,p=q;
update(a[p].r),update(p);
}
inline void zag(int &p)
{
int q=a[p].r;
a[p].r=a[q].l,a[q].l=p,p=q;
update(a[p].l),update(p);
}
inline void Insert(int &p,int x)
{
if(!p){p=NEW(x);return;}
if(a[p].num==x){a[p].cnt++,update(p);return;}
if(x<a[p].num)
{
Insert(a[p].l,x);
if(a[a[p].l].data>a[p].data) zig(p);
}
else
{
Insert(a[p].r,x);
if(a[a[p].r].data>a[p].data) zag(p);
}
update(p);
}
inline void Remove(int &p,int x)
{
if(a[p].num==x)
{
if(a[p].cnt>1) {a[p].cnt--,update(p);return;}
if(a[p].l||a[p].r)
{
if(!a[p].r||a[a[p].l].data>a[a[p].r].data) zig(p),Remove(a[p].r,x);
else zag(p),Remove(a[p].l,x);
update(p);
}
else p=0;
return;
}
if(x<a[p].num) Remove(a[p].l,x);
else Remove(a[p].r,x);
update(p);
}
inline int val(int p,int x)
{
if(!p) return 0;
if(a[a[p].l].size>=x) return val(a[p].l,x);
if(a[a[p].l].size+a[p].cnt>=x) return a[p].num;
return val(a[p].r,x-a[a[p].l].size-a[p].cnt);
}
inline int sum(int p,int x)
{
if(!p) return 0;
if(a[p].num==x) return a[a[p].l].size;
if(x<a[p].num) return sum(a[p].l,x);
return a[a[p].l].size+a[p].cnt+sum(a[p].r,x);
}
inline int pre(int p,int x)
{
if(!p) return -inf;
if(x>a[p].num) return max(pre(a[p].r,x),a[p].num);
return pre(a[p].l,x);
}
inline int nxt(int p,int x)
{
if(!p) return inf;
if(x<a[p].num) return min(nxt(a[p].l,x),a[p].num);
return nxt(a[p].r,x);
}
int main()
{
n=get_int();build();
for(int i=1;i<=n;i++)
{
int tag=get_int(),x=get_int();
switch(tag)
{
case 0:
Insert(root,x);
break;
case 1:
Remove(root,x);
break;
case 2:
print(val(root,x+1)),putchar('\n');
break;
case 3:
print(sum(root,x)-1),putchar('\n');
break;
case 4:
ans=pre(root,x),print(ans==-inf?-1:ans),putchar('\n');
break;
case 5:
ans=nxt(root,x),print(ans==inf?-1:ans),putchar('\n');
break;
}
}
return 0;
}