Codeforces-706D Vasiliy's Multiset

题目大意:

最开始的时候有一个集合,集合里面只有一个元素0,现在有q次操作,操作分为3种:

+ x: 表示向集合中添加一个元素x

- x:表示删除集合中值为x的一个元素

? x:表示查询集合中与x异或的最大值为多少

解题思路:

乱搞。

可以用一个multiset来维护这个集合。这样前两个操作就是非常简单的了,关键在于最后一个操作。

对于异或来说,比如说如果给你一个数11,另外一个数是30 bit之内的数,他们的异或最大是多少?答案是1073741823。

怎么得到的呢?

先把11转换成二进制:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0

那么与11异或之后获得最大值就是

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1也就是1073741823

而获得这个最大值的与11异或的那个数就是1073741812

所以我们可以维护一个字典树来获得这个结果,字典树保存的就是每个数的二进制串,然后每次查询的时候能取相反就取相反。

不过我们是用multiset来维护这个集合,那么其实对于第三个操作也可以按照上面的思想来做。

对于任意的一个x,每次获取它的一个位上的值,然后取反,将这个值加入到tmp的这个位上,然后进行判断,在multiset里面查询,如果在tmp到tmp+(1<<i)这个区间内有这个值,那么说明这个值可取,如果不存在,则不可取,然后把这个值从tmp的位上取下即可。具体看代码。

代码:

#include <set>
#include <iostream>
#include <algorithm>
using namespace std;
//#define DEBUG 1
multiset<int> s;
multiset<int>::iterator it;
int bit(int x, int i) {
	return (x >> i) & 1;
}
int check(int a, int b) {
	it = s.lower_bound(a);
	if (it == s.end()) return 0;
	if ((*it) < b) return 1;
	else return 0;
}
int solve(int x) {
	int tmp, ans = 0;
	for (int i = 30; i >= 0; --i) {
		tmp = bit(x, i);
		if (!tmp) ans |= (1LL << i);
		if (!check(ans, ans + (1LL << i))) ans ^= (1LL << i);
	}
	return (ans ^ x);
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	char op;
	int q, x;
	s.insert(0);
	cin >> q;
	while (q--) {
		cin >> op >> x;
		if (op == '+') {
			s.insert(x);
		} else if (op == '-') {
			it = s.find(x);
			s.erase(it);
		} else {
			cout << solve(x) << endl;
		}
	}
#ifdef DEBUG
	system("pause");
#endif // DEBUG
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值