题目描述
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
插入
x
x
x数
删除
x
x
x数(若有多个相同的数,因只删除一个)
查询
x
x
x数的排名(排名定义为比当前数小的数的个数
+
1
+1
+1。若有多个相同的数,因输出最小的排名)
查询排名为
x
x
x的数
求
x
x
x的前驱(前驱定义为小于
x
x
x,且最大的数)
求
x
x
x的后继(后继定义为大于
x
x
x,且最小的数)
输入输出格式
输入格式:
第一行为
n
n
n,表示操作的个数,下面
n
n
n行每行有两个数
o
p
t
opt
opt和
x
x
x,
o
p
t
opt
opt表示操作的序号( $ 1 \leq opt \leq 6 $ )
输出格式:
对于操作
3
,
4
,
5
,
6
3,4,5,6
3,4,5,6每行输出一个数,表示对应答案
输入输出样例
输入样例#1:
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
输出样例#1:
106465
84185
492737
说明
时空限制:1000ms,128M
1.n的数据范围: $ n \leq 100000 $
2.每个数的数据范围:
[
−
10
7
,
10
7
]
[-{10}^7, {10}^7]
[−107,107]
题解
一道裸的平衡树题。。。
就拿来练非旋Treap吧。。。
#code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define Max 100000
#define max 10000001
#define min -10000001
using namespace std;
int tr[Max+1][2];
int sum[Max+1];
int fa[Max+1];
int heap[Max+1];
int num[Max+1];
bool del[Max+1];
int n,Q,I,i,j,k,l,x,y,X,Fs,Ls,type,root,Find,Find2,now,fa1,fa2;
void up(int t) {sum[t]=sum[tr[t][0]]+sum[tr[t][1]]+1;}
void merge(int Fa,int son,int x,int y)
{
if (heap[x]<heap[y])
{
tr[Fa][son]=x;
fa[x]=Fa;
if (tr[x][1])
merge(x,1,tr[x][1],y);
else
{
sum[x]+=sum[y];
tr[x][1]=y;
fa[y]=x;
}
}
else
{
tr[Fa][son]=y;
fa[y]=Fa;
if (tr[y][0])
merge(y,0,x,tr[y][0]);
else
{
sum[y]+=sum[x];
tr[y][0]=x;
fa[x]=y;
}
}
if (Fa) up(Fa);
}
void split(int Fa1,int Fa2,int t,int k)
{
if (sum[tr[t][0]]>=k)
{
if (!fa1) fa1=t;
if (fa[t])
{
tr[fa[t]][tr[fa[t]][1]==t]=0;
up(fa[t]);
}
tr[Fa1][0]=t;
fa[t]=Fa1;
if (k && tr[t][0])
split(t,Fa2,tr[t][0],k);
if (Fa1) up(Fa1);
}
else
{
if (!fa2) fa2=t;
if (fa[t])
{
tr[fa[t]][tr[fa[t]][1]==t]=0;
up(fa[t]);
}
tr[Fa2][1]=t;
fa[t]=Fa2;
if (tr[t][1])
split(Fa1,t,tr[t][1],k-sum[tr[t][0]]-1);
if (Fa2) up(Fa2);
}
}
int find(int t,int k)
{
if (sum[tr[t][0]]>=k)
return find(tr[t][0],k);
else
if (sum[tr[t][0]]+1==k)
return num[t];
else
return find(tr[t][1],k-sum[tr[t][0]]-1);
}
void find1(int t,int s)
{
if (tr[t][0] && num[t]>=s)
find1(tr[t][0],s);
else
if (tr[t][1] && num[t]<s)
find1(tr[t][1],s);
if (num[t]<s)
{
Find2+=sum[tr[t][0]]+1;
if (num[t]>Find)
Find=num[t];
}
}
void find2(int t,int s)
{
if (tr[t][1] && num[t]<=s)
find2(tr[t][1],s);
else
if (tr[t][0] && num[t]>s)
find2(tr[t][0],s);
if (num[t]>s && num[t]<Find)
Find=num[t];
}
int gf(int t)
{
for (;fa[t];t=fa[t]);
return t;
}
int main()
{
srand(time(NULL));
scanf("%d",&Q);
fo(i,1,Max)
{
heap[i]=rand()*32768+rand();
sum[i]=1;
}
I=1;
n=0;
now=0;
for (;Q;Q--)
{
scanf("%d%d",&type,&x);
switch (type)
{
case 1:
{
num[++n]=x;
if (!now)
{
now++;
root=n;
break;
}
Find=min;
Find2=0;
find1(root,x);
if (!Find2)
merge(0,0,n,root);
else
if (Find2==now)
merge(0,0,root,n);
else
{
fa1=0,fa2=0;
split(0,0,root,Find2);
merge(0,0,fa2,n);
merge(0,0,gf(n),fa1);
}
root=gf(n);
now++;
break;
}
case 2:
{
Find=min;
Find2=0;
find1(root,x+1);
if (Find!=x) break;
Find=min;
Find2=0;
find1(root,x);
if (!Find2)
{
fa1=0,fa2=0;
split(0,0,root,1);
root=fa1;
}
else
if (Find2+1==now)
{
fa1=0,fa2=0;
split(0,0,root,now-1);
root=fa2;
}
else
{
fa1=0,fa2=0;
split(0,0,root,Find2);
j=fa1,k=fa2;
fa1=0,fa2=0;
split(0,0,j,1);
merge(0,0,k,fa1);
root=gf(k);
}
now--;
break;
}
case 3:
{
Find2=0;
find1(root,x);
printf("%d\n",Find2+1);
break;
}
case 4:
{
printf("%d\n",find(root,x));
break;
}
case 5:
{
Find=min;
Find2=0;
find1(root,x);
printf("%d\n",Find);
break;
}
case 6:
{
Find=max;
find2(root,x);
printf("%d\n",Find);
break;
}
}
}
}