1. 程式人生 > >HDU 4825 Xor Sum (01字典樹)

HDU 4825 Xor Sum (01字典樹)

題意:給你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;
}