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