Description
设计数据结构支持:
1 x 若x不存在,插入x
2 x 若x存在,删除x
3 输出当前最小值,若不存在输出-1
4 输出当前最大值,若不存在输出-1
5 x 输出x的前驱,若不存在输出-1
6 x 输出x的后继,若不存在输出-1
7 x 若x存在,输出1,否则输出-1
Input
第一行给出n,m 表示出现数的范围和操作个数
接下来m行给出操作
n<=10^6,m<=2*10^6,0<=x<n
Output
Sample Input
10 11
1 1
1 2
1 3
7 1
7 4
2 1
3
2 3
4
5 3
6 2
1 1
1 2
1 3
7 1
7 4
2 1
3
2 3
4
5 3
6 2
Sample Output
1
-1
2
2
2
-1
-1
2
2
2
-1
HINT
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ZKW线段树~
据说这题卡treap,哼。
ZKW线段树实在是太神奇辣!用位运算解决递归的神奇方法,但是在这道题里面如果没有a[i]<n的限制应该是不能用的。
注意a[i]>=0,所以我们在计算的时候先把a+1,输出的时候再减去。
数组要开得很大很大很大。
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,k,pos,x,c[3000010];
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void add(int u)
{
u+=k;
if(c[u]) return;
for(;u;u>>=1) c[u]++;
}
void del(int u)
{
u+=k;
if(!c[u]) return;
for(;u;u>>=1) c[u]--;
}
int cal_min()
{
if(!c[1]) return 0;
int u;
for(u=1;u<=k;u=c[u<<1] ? u<<1:u<<1|1);
return u-k;
}
int cal_max()
{
if(!c[1]) return 0;
int u;
for(u=1;u<=k;u=c[u<<1|1] ? u<<1|1:u<<1);
return u-k;
}
int last(int u)
{
for(u+=k;u^1;u>>=1) if(u&1 && c[u>>1]>c[u]) break;
if(u==1) return 0;
for(u^=1;u<=k;u=c[u<<1|1] ? u<<1|1:u<<1);
return u-k;
}
int next(int u)
{
for(u+=k;u^1;u>>=1) if(~u&1 && c[u>>1]>c[u]) break;
if(u==1) return 0;
for(u^=1;u<=k;u=c[u<<1] ? u<<1:u<<1|1);
return u-k;
}
int exi(int u)
{
return c[u+k] ? 1:-1;
}
int main()
{
n=read();m=read();
for(k=1;k<=n;k<<=1);
while(m--)
{
pos=read();
switch(pos)
{
case 1:x=read()+1;add(x);break;
case 2:x=read()+1;del(x);break;
case 3:printf("%d\n",cal_min()-1);break;
case 4:printf("%d\n",cal_max()-1);break;
case 5:x=read()+1;printf("%d\n",last(x)-1);break;
case 6:x=read()+1;printf("%d\n",next(x)-1);break;
case 7:x=read()+1;printf("%d\n",exi(x));break;
}
}
return 0;
}