普通van Emde Boas树
题意不再赘述见题面:设计数据结构支持:
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
数据范围和操作数都是1e6级别的,所以普通的set或者treap用起来很方便的是会超时的,所以怎么解决呢?
因为拉的是有关权值线段树的专题,所以很容易想到这个,空间也不会爆,不用离散化,那么每个叶节点代表这个值是否出现过即可,每个节点储存当前区间的最值,只有操作5、6相对比较麻烦,如果前驱的话相当于求[0,x-1]中存在的数的最大值,反之求[x+1,n-1]的最小值,其他的操作比较简单。但写出来竟然TLE了,考虑到数据量比较大。于是加了个快读,8000+ms。荣神将递归改成循环式查找6000+ms,ORZ。
权值线段树+快速读:
const int N=1e6+10;
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int sc()
{
char ch=nc();
int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
struct node
{
int l,r,num,mi,ma;
} a[N<<2];
int n,m,c[N];
void pushup(int k)
{
a[k].num=a[k*2].num+a[k*2+1].num;
a[k].mi=min((a[k*2].num?a[k*2].mi:INF),(a[k*2+1].num?a[k*2+1].mi:INF));
a[k].ma=max((a[k*2].num?a[k*2].ma:0),(a[k*2+1].num?a[k*2+1].ma:0));
}
void build(int l,int r ,int k)
{
a[k].l=l,a[k].r=r,a[k].num=0,a[k].mi=INF,a[k].ma=0;
if(l==r)
{
a[k].ma=a[k].mi=l;
c[l]=0;
return ;
}
int mid=(l+r)/2;
build(l,mid,2*k);
build(mid+1,r,2*k+1);
}
void update(int id,int f,int k)//支持插入或删除
{
if(a[k].l==id&&a[k].r==id)
{
if(f==1&&!a[k].num)
{
a[k].num^=1;
c[id]=1;
}
else if(f==2&&a[k].num)
{
a[k].num^=1;
c[id]=0;
}
return ;
}
int mid=(a[k].l+a[k].r)/2;
if(id<=mid) update(id,f,k*2);
else update(id,f,k*2+1);
pushup(k);
}
int query(int l,int r,int f,int k)//求前驱或后继
{
if(r<l) return INF;
if(a[k].l==l&&a[k].r==r)
{
if(!a[k].num) return INF;
return f==1?a[k].ma:a[k].mi;
}
int mid=(a[k].l+a[k].r)/2;
if(r<=mid) return query(l,r,f,2*k);
if(l>mid) return query(l,r,f,2*k+1);
else
{
int tmp1=query(l,mid,f,2*k);
int tmp2=query(mid+1,r,f,2*k+1);
if(tmp1==INF&&tmp2!=INF) return tmp2;
else if(tmp1!=INF&&tmp2==INF) return tmp1;
return (f==1)?max(tmp1,tmp2):min(tmp1,tmp2);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
build(0,n,1);
while(m--)
{
int x,y;
x=sc();
if(x==3||x==4)
{
if(!a[1].num) puts("-1");
else printf("%d\n",x==3?a[1].mi:a[1].ma);
continue;
}
y=sc();
if(x==1||x==2) update(y,x,1);
else if(x==7)
{
if(c[y]) puts("1");
else puts("-1");
}
else
{
int tmp=INF;
if(x==5) tmp=query(0,y-1,1,1);
else tmp=query(y+1,n-1,2,1);
if(tmp==INF) puts("-1");
else printf("%d\n",tmp);
}
}
}
return 0;
}
荣神大佬:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 1000010
#define LEFT (pos << 1)
#define RIGHT (pos << 1 | 1)
using namespace std;
int range, asks, M;
int tree[MAX << 2];
inline void Modify(int pos, int c)
{
tree[pos] += c;
for (; pos; pos >>= 1)
tree[pos] += c;
}
inline int GetMin(int pos)
{
if (!tree[pos])
return 0;
while (pos <= M)
{
if (tree[LEFT])
pos = LEFT;
else
pos = RIGHT;
}
return pos - M;
}
inline int GetMax(int pos)
{
if (!tree[pos])
return 0;
while (pos <= M)
{
if (tree[RIGHT])
pos = RIGHT;
else
pos = LEFT;
}
return pos - M;
}
inline int GetPred(int x)
{
int pos = x + M;
while (1)
{
if (pos == 1)
return 0;
if (pos & 1 && tree[pos ^ 1])
return GetMax(pos ^ 1);
pos >>= 1;
}
return 0;
}
inline int GetSucc(int x)
{
int pos = x + M;
while (1)
{
if (pos == 1)
return 0;
if (!(pos & 1) && tree[pos ^ 1])
return GetMin(pos ^ 1);
pos >>= 1;
}
return 0;
}
int main()
{
cin >> range >> asks;
for (M = 1; M <= range; M <<= 1)
;
for (int x, flag, i = 1; i <= asks; ++i)
{
scanf("%d", &flag);
if (flag == 1)
{
scanf("%d", &x);
++x;
if (!tree[M + x])
Modify(M + x, 1);
}
else if (flag == 2)
{
scanf("%d", &x);
++x;
if (tree[M + x])
Modify(M + x, -1);
}
else if (flag == 3)
printf("%d\n", GetMin(1) - 1);
else if (flag == 4)
printf("%d\n", GetMax(1) - 1);
else if (flag == 5)
{
scanf("%d", &x);
++x;
printf("%d\n", GetPred(x) - 1);
}
else if (flag == 6)
{
scanf("%d", &x);
++x;
printf("%d\n", GetSucc(x) - 1);
}
else
{
scanf("%d", &x);
++x;
printf("%d\n", tree[x + M] ? 1 : -1);
}
}
return 0;
}