HDU 4825 Xor Sum (01字典树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/PK__PK/article/details/82830612

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4825

题意:给你n个数字,再给你m次询问,每次询问给你一个数S,求n个数中和S异或最大的值。

题解:n方绝对超时。所以需要用的01字典树这个东西。

01字典树:本质和字典树是一样的。只不过他每个节点只存0和1这两个东西。具体来说一下。我们可以把一个数字转成2进制数,把这个数字用来建树。但是这个树是从高位置向低位置建树的。比如3不是11,而是0000……11。

对于建树来说。若当前这个位置为1那么就在tire【root】【1】这个位置加一个节点。若是0那就trie【root】【0】这个位置加一个节点。然后root = tire【root】【1/0】;

对于查询来说。每次判断tire【root】【i^1】是否有值。有就让root = trie【root】【i^1】,没有就root = tire【root】【i】;

具体看代码注释:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
typedef long long ll;
using namespace std;

const int maxn = 1e5+7;

int ch[32*maxn][2];
ll val[32*maxn];
int sz;

void init(){
	memset(ch[0],0,sizeof(ch[0]));
	sz = 1;
}

void insert(ll a){  // 插入a 
	int u = 0; // 从根节点0插入 
	for(int i = 32 ; i >= 0 ; i --){ // 从高位开始遍历。 
		int c = ((a >> i) & 1);  // 判断 i 位置 是 0 还是 1 
		if(!ch[u][c]){   // 若当前节点没有值 
			memset(ch[sz],0,sizeof(ch[sz]));  // 建立一个新的节点。 
			val[sz] = 0;
			ch[u][c] = sz++;
		}
		u = ch[u][c]; // 遍历到u的第c个儿子节点 
	}
	val[u] = a; // 叶子节点赋值 
}

ll query(ll a){
	int u = 0;
	for(int i = 32 ; i >= 0 ; i --){
		int c = ((a >> i) & 1);
		if(ch[u][c^1]) u = ch[u][c^1]; // 向不同的地方走 
		else u = ch[u][c];
	}
	return val[u]; //返回叶子节点存的值。 
}
ll a[maxn];
int main(){
	int t,n,m,kase = 0;
	scanf("%d",&t);
	while(t--){
		init();
		scanf("%d%d",&n,&m);
		for(int i = 1 ; i <= n ; i ++){
			scanf("%lld",&a[i]);
			insert(a[i]); // 插入值 
		}
		printf("Case #%d:\n",++kase);
		for(int i = 1 ; i <= m ; i ++){
			ll x;
			scanf("%lld",&x);
			printf("%lld\n",query(x));  // 查询值 
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/PK__PK/article/details/82830612