【2018/08/21测试T2】【SDOJ 3772】位运算

【题目】

题目描述:

有q次操作,每次操作是以下两种:
1、 加入一个数到集合中
2、 查询,查询当前数字与集合中的数字的最大异或值,最大 and 值,最大 or 值

输入格式:

第一行 1 个正整数 Q 表示操作次数
接下来 Q 行,每行 2 个数字,第一个数字是操作序号 OP(1 , 2),第二个数字是 X 表示操作的数字

输出格式:

输出查询次数行,每行3  个整数,空格隔开,分别表示最大异或值,最大 and 值,最大 or 值

样例数据:

【样例1】

输入

5
1 2
1 3
2 4
1 5
2 7

输出

7 0 7
5 5 7

解释

询问 4 时,已插入 2、3,最大异或值为4^3=7,最大 and 值为4&3或4&2=0,最大 or 值为4|3=7
询问 7 时,已插入 2、3、5,最大异或值为7^2=5,最大 and 值为7&5=5,最大 or 值为7|2=7|3=7|5=7

【样例2】

输入

10
1 194570
1 202332
1 802413
2 234800
1 1011194
2 1021030
2 715144
2 720841
1 7684
2 85165

输出

1026909 201744 1032061
879724 984162 1048062
655316 682376 1043962
649621 683464 1048571
926039 85160 1011199

备注:

对于 10% 的数据保证 1 ≤ Q ≤ 5000
对于另 10% 的数据保证 X < 1024
对于另 40% 的数据保证 1 ≤ Q ≤ 100000
对于所有数据保证 1 ≤ Q ≤ 1000000 , 1 ≤ X ≤ 2^{20},保证第一个操作为 1 操作。

【分析】

先考虑异或,由于异或是相同为 0,不同为 1,我们就以集合中的数(换算成二进制)构建Trie树,找的时候从高位向低位找,每次都尽量往与自己不同的数走(比如 0 就走 1,1 就走 0),实在不行才往相同的数走,这样保证答案最大

接下来是,它们本质上差不多,这里就细讲一下与。那么我们还是从高位向低位贪心,由于与是都为 1 才为 1,所以当某一位为 0 时,既可以填 1,又可以填 0,这个时候我们只需要标记子集,默认填 0 即可

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1<<19+5
using namespace std;
int t,trie[N][2];
bool sub[N];
void mark(int x)
{
	int i;
	sub[x]=true;
	for(i=0;i<20;++i)
	    if((x>>i&1)&&(!sub[x^(1<<i)]))
		mark(x^(1<<i));
}
void insert(int x)
{
	int i,k,p=0;
	for(i=19;~i;--i)
	{
		k=(x>>i&1?1:0);
		if(!trie[p][k])
		  trie[p][k]=++t;
		p=trie[p][k];
	}
}
int askxor(int x)
{
	int i,k,p=0,now=0;
	for(i=19;~i;--i)
	{
		k=(x>>i&1?0:1);
		if(trie[p][k])
		{
			p=trie[p][k];
			if(k)  now|=1<<i;
		}
		else
		{
			p=trie[p][k^1];
			if(k^1)  now|=1<<i;
		}	
	}
	return now;
}
int askand(int x)
{
	int i,now=0;
	for(i=19;~i;--i)
	    if((x>>i&1)&&sub[now|1<<i])
	        now|=1<<i;
	return now;
}
int askor(int x)
{
	int i,now=0;
	for(i=19;~i;--i)
	    if((!(x&(1<<i)))&&sub[now|1<<i])
	        now|=1<<i;
	return now;
}	
int main()
{
//	freopen("xorand.in","r",stdin);
//	freopen("xorand.out","w",stdout);
	int n,i,s,x;
	scanf("%d",&n);
	for(i=1;i<=n;++i)
	{
		scanf("%d%d",&s,&x);
		if(s==1)
		{
			mark(x);
			insert(x);
		}
		else
		{
			printf("%d ",askxor(x)^x);
			printf("%d ",askand(x)&x);
			printf("%d\n",askor(x)|x);
		}
	}
//	fclose(stdin);
//	fclose(stdout);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/81909489
今日推荐