BZOJ 3685 普通van Emde Boas树

12 篇文章 0 订阅

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


Sample Output

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;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值