思想:
01字典树就是普通的字典树加上贪心策略的查找,如果是求最大异或值,则每次都去找跟自己的那一位异或为1的,求最小值则相反。
应用:
1.求[l,r]的异或和 。
由X xor X = 0 ; 0 xor Y = Y;有【l,r】 = 【1,r】 XOR 【1,l - 1】 这样在一颗加入了r 前的所有前缀异或和的01字典树上查找【1,r】就能得到以r为右边界的最大异或和。
2.求最大异或。最小异或。
例题:最大异或。
HDU4825
Code:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 3e5+66;
int a[AX];
typedef struct Trie_Node{
struct Trie_Node* next1[2];
int val;
}TrieNode,*Trie;
TrieNode* Trie_creatroot(){
TrieNode* root = new TrieNode();
memset( root -> next1 , 0 , sizeof(root->next1) );
return root ;
}
void insert( Trie node , int x ){
for( int i = 31 ; i >= 0 ; i-- ){
int c = ( x >> i ) & 1 ;
if( node -> next1[c] == NULL ){
node -> next1[c] = Trie_creatroot();
}
node = node -> next1[c];
}
node -> val = x;
}
int Querry( Trie node , int x ){
for( int i = 31 ; i >= 0 ; i-- ){
int c = ( x >> i ) & 1 ;
if( node -> next1[c^1] ) node = node -> next1[c^1];
else node = node -> next1[c];
}
return node -> val;
}
int main(){
int T;
int n , m ;
scanf("%d",&T);
int Case = 0 ;
while( T-- ){
scanf("%d%d",&n,&m);
int x;
Trie root = Trie_creatroot();
for( int i = 0 ; i < n ; i++ ){
scanf("%d",&x);
insert( root , x );
}
int res = -1;
printf("Case #%d:\n",++Case);
for( int i = 0 ; i < m; i++ ){
scanf("%d",&x);
printf("%d\n",Querry(root,x));
}
}
return 0 ;
}
最小异或+删除操作。(每次求得两个数的异或后,就将该数从树中删除)
C. Perfect Security
Code:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 3e5+66;
int a[AX];
typedef struct Trie_Node{
struct Trie_Node* next1[2];
int val;
int count ;
}TrieNode,*Trie;
TrieNode* Trie_creatroot(){
TrieNode* root = new TrieNode();
root -> count = 0 ;
memset( root -> next1 , 0 , sizeof(root->next1) );
return root ;
}
void insert( Trie node , int x ){
for( int i = 31 ; i >= 0 ; i-- ){
int c = ( x >> i ) & 1 ;
if( node -> next1[c] == NULL ){
node -> next1[c] = Trie_creatroot();
}
node = node -> next1[c];
node -> count ++;
}
node -> val = x;
}
int Querry( Trie node , int x ){
for( int i = 31 ; i >= 0 ; i-- ){
int c = ( x >> i ) & 1 ;
if( node -> next1[c] && node -> next1[c] -> count ) node = node -> next1[c];
else node = node -> next1[c^1];
}
printf("%d ",(node -> val ^ x ));
return node -> val ;
}
void Del( Trie node , int x ){
for( int i = 31 ; i >= 0 ; i-- ){
int c = ( x >> i ) & 1 ;
node = node -> next1[c];
node -> count --;
if( !node -> count ) node == NULL;
}
}
int main(){
int n ;
scanf("%d",&n);
int x ;
Trie root = Trie_creatroot() ;
for( int i = 0 ; i < n ; i++ ){
scanf("%d",&a[i]);
}
for( int i = 0 ; i < n ; i++ ){
scanf("%d",&x);
insert( root , x );
}
for( int i = 0 ; i < n ; i++ ){
int ans = Querry(root , a[i]);
//cout << "ans :" <<ans << endl;
Del(root ,ans);
}
printf("\n");
return 0 ;
}