标签:sizeof mem 位置 根据 二叉树 不同 十进制 pre ring
传送门:>Here<
题意:给出一个集合,包含N个数,每次询问给出一个数x,问x与集合中的一个数y异或得到最大值时,y是多少?
解题思路
由于N,M非常大,暴力显然不行。抓住重点是异或,所以可以把数字转换为二进制。这又让我们想到了字典树……
根据二进制中数的定理:任何一个位置靠前的数比后面所有的数加起来都大。就好像十进制,100比99大。因此异或的时候要尽量让靠前的数与它不一样。
把集合内的所有数字根据二进制建立字典树。很明显因为是二进制只有0和1,当前的trie一定是一棵二叉树。因此我们可以拿当前数到trie里面跑一遍,因为trie是前缀树,所以先碰到的肯定是二进制前的。如果有不同的路(就是说如果当前数字为0,看有没有通往1的路)就走,否则没办法
注意到数字最多只有32位。因为要建立前缀树,所以如果数字太小可以补充前导零。每一次用一个bool数组记录一下数字的各个位即可
Code
End数组要清零
/*By DennyQi*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int MAXN = 3300010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar(); if(c == ‘-‘) w = -1, c = getchar(); while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) +(x << 1) + c - ‘0‘, c = getchar(); return x * w; } int T,N,M,x; int ch[MAXN][2],cnt,End[MAXN]; bool num[70]; inline void Convert(int x){ memset(num, 0, sizeof(num)); for(int i = 33; x > 0; --i, x>>=1) num[i] = x%2; } inline void Insert(int x){ Convert(x); int u = 0; for(int i = 1; i <= 33; ++i){ if(!ch[u][num[i]]) ch[u][num[i]] = ++cnt; u = ch[u][num[i]]; } End[u] = x; } inline int Query(int x){ Convert(x); int u = 0, res = 0; for(int i = 1; i <= 33; ++i){ if(!ch[u][!num[i]]) u = ch[u][num[i]]; else u = ch[u][!num[i]]; if(End[u]) res = Max(res, End[u]); } return res; } inline void Init(){ cnt = 0; memset(ch, 0, sizeof(ch)); memset(End, 0, sizeof(End)); } int main(){ T=r; for(int _c = 1; _c <= T; ++_c){ printf("Case #%d:\n",_c); Init(); N=r,M=r; for(int i = 1; i <= N; ++i) x=r, Insert(x); for(int i = 1; i <= M; ++i) x=r, printf("%d\n", Query(x)); } return 0; }
标签:sizeof mem 位置 根据 二叉树 不同 十进制 pre ring
原文地址:https://www.cnblogs.com/qixingzhi/p/9425017.html