01字典树在异或问题的查询上十分高效。
01字典树是按位插入和查询的。因为如果一个数,它的高位值较大,那么这个数的值较大。所以我们插入和查询时是从最高位开始进行的。
可以开一个辅助数组val来记录原数值。
插入:
#define ll long long int n,m; int trie[32*MAXN][2]; ll val[32*MAXN]; int tot; void insert(ll d) { int root=0; for(int i=32;i>=0;i--) { int id=(d>>i)&1;//获得这一个bit位的值 if(!trie[root][id]) trie[root][id]=++tot; root=trie[root][id]; } val[root]=d; }
查询:
ll query(ll d) { int root=0; for(int i=32;i>=0;i--) { int id=(d>>i)&1; if(trie[root][id^1]) root=trie[root][id^1]; else root=trie[root][id]; } return val[root]; }
例题:HDU - 4825
给出一个S,在数组里找到一个数K,使得K^S最大。
#include<stdio.h> #include<math.h> #include<string.h> #include<algorithm> using namespace std; #define MAXN 100005 #define ll long long int n,m; int trie[32*MAXN][2]; ll val[32*MAXN]; int tot; void insert(ll d) { int root=0; for(int i=32;i>=0;i--) { int id=(d>>i)&1;//获得这一个bit位的值 if(!trie[root][id]) trie[root][id]=++tot; root=trie[root][id]; } val[root]=d; } ll query(ll d) { int root=0; for(int i=32;i>=0;i--) { int id=(d>>i)&1; if(trie[root][id^1]) root=trie[root][id^1]; else root=trie[root][id]; } return val[root]; } int main() { int cas; scanf("%d",&cas); for(int tt=1;tt<=cas;tt++) { scanf("%d%d",&n,&m); memset(trie,0,sizeof trie); for(int i=0;i<n;i++) { int d; scanf("%d",&d); insert(d); } printf("Case #%d:\n",tt); for(int i=0;i<m;i++) { ll d; scanf("%lld",&d); printf("%lld\n",query(d)); } } return 0; }