HDU 4285 - Xor Sum(01字典树)
Xor Sum
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 10153 Accepted Submission(s): 4176
Problem Description
Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大。Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助。你能证明人类的智慧么?
Input
输入包含若干组测试数据,每组测试数据包含若干行。
输入的第一行是一个整数T(T < 10),表示共有T组数据。
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。
Output
对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
对于每个询问,输出一个正整数K,使得K与S异或值最大。
Sample Input
2
3 2
3 4 5
1
5
4 1
4 6 5 6
3
Sample Output
Case #1:
4
3
Case #2:
4
题目大意:
给出 t 组数据,对于每组数据,输入 n q 表示n 个数和q 个询问,接下来输入n个数,然后再输出q个数,对于每个询问,输出 n 个数中与 该数异或值最大的数。
解题思路:
01字典树模板题,建树以后直接插入查询即可。
Code:
#pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 50;
int tot = 1;
ll val[N * 32], ch[N * 32][2];
void init()
{
memset(ch, 0, sizeof ch);
memset(val, 0, sizeof val);
tot = 1;
}
void insert(ll x)//插入的过程
{
int u = 0;
for (int i = 31; i >= 0; i --)
{
int v = (x >> i) & 1;//从大到小依次按位&1
if (!ch[u][v])//如果这个节点没有被访问过则插入新节点
{
ch[tot][0] = ch[tot][1] = 0;//下一个节点初始化
ch[u][v] = tot++;//当前的u v(0或1)指向下一个节点
val[tot] = 0;//因为没到最底层节点,所以 = 0
}
u = ch[u][v];//类似于指针,指向下一个编号
}
val[u] = x;
}
ll query(ll x)
{
int u = 0;
for (int i = 31; i >= 0; i --)
{
int v = (x >> i) & 1;
if (ch[u][v ^ 1]) u = ch[u][v ^ 1];//每次去找和v不一样的,使异或值最大
else u = ch[u][v];
}
return val[u];
}
int main()
{
ios::sync_with_stdio(false);
int t, k = 1;
cin >> t;
while (t--)
{
cout << "Case #" << k++ << ':' << endl;
init();
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; i ++)
{
int s;
cin >> s;
insert(s);
}
while (q--)
{
ll s;
cin >> s;
cout << query(s) << endl;
}
}
return 0;
}