hdu4825

hdu4825 Xor Sum
传送门
题意
给定一个集合,包含n个正整数,发起m次询问,每次询问包含一个正整数s,每次在集合中找到一个正整数k,使得s与k的异或值最大,输出正整数k。
1<=n,m<=100000,正整数不超过\(2^{32}\)
题解
暴力寻找必然超时,需要优化查找方法。
假设询问的正整数s的二进制形式为1101011100001101011000101101010(31位),想要异或值最大,首先在集合中查找最高位异或值为1的数,也就是最高位为0的数。如果存在,则继续在这些数里寻找次高位异或值为1的数,否则就在所有数中寻找次高位异或值为1的数,以此类推,31位全部找完之后,得到的就是异或值最大时的情形。
预处理将集合中的所有数建成一棵Trie树,在线处理询问。
每一次询问,查找的时间复杂度为\(O(logn)\),一共m次询问,总时间复杂度为\(O(mlogn)\)
以样例二为例子,集合中的数为4(100),6(110),5(101),6(110),询问的数为3(011),建立Trie树,则沿着图中红色路径,异或值最大,异或的数为4。

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;

int T,cas,n,m,son[3200010][2],number[3200010],id;

void insert(int x){
	int p=0;
	for(int i=30;i>=0;i--){
		int& t=son[p][(x>>i)&1];
		if(!t) t=++id;
		p=t;
	}
	number[p]=x;
}

int query(int x){
	int p=0;
	for(int i=30;i>=0;i--){
		int t=son[p][!((x>>i)&1)];
		if(t){
			p=t;
		}
		else{
			p=son[p][(x>>i)&1];
		}
	}
	return number[p];
}

int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d %d",&n,&m);
		memset(son,0,sizeof(son));
		id=0;
		for(int i=1;i<=n;i++){
			int x;
			scanf("%d",&x);
			insert(x);
		}
		printf("Case #%d:\n",++cas);
		while(m--){
			int x;
			scanf("%d",&x);
			printf("%d\n",query(x));
		}
	}
	return 0;
}
posted @ 2020-05-30 21:10  fxq1304  阅读(89)  评论(0编辑  收藏  举报