先将题意转换为求A和B中的最小最优异或对并排序输出
所以可以建两颗trie并同时在两颗树内贪心跳转找最小异或对排序输出
贪心匹配可以建cnt数组记录当前节点个数,匹配时走过节点个数就直接减一
最优匹配顺序必然是先相同0 0 , 1 1 再不同 0 1 , 1 0
完!
/*
Zeolim - An AC a day keeps the bug away
*/
//pragma GCC optimize(2)
#include <bits/stdc++.h>
#include<queue>
using namespace std;
#define mp(x, y) make_pair(x, y)
#define fr(x, y, z) for(int x = y; x < z; ++x)
typedef long long ll;
typedef double ld;
typedef std::pair<int, int> pii;
typedef std::vector <short> vi;
//typedef __int128 ill;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 1e9 + 7;
const int MAXN = 2e6 + 10;
int t, n;
int mov[4][2] = { {0, 0},{1, 1},{0, 1}, {1, 0}};
struct Tre
{
int trie[MAXN][2], cnt;
int pre[MAXN];
void init()
{
fr(i, 0, cnt)
memset(trie[i], 0, sizeof(trie[i])), pre[i] = 0;
cnt = 1;
}
void insert(ll x)
{
int to = 1;
for(int i = 30; i >= 0; --i)
{
int val = x >> i & 1;
if( !trie[to][val])
trie[to][val] = ++cnt;
to = trie[to][val];
++pre[to];
}
}
};
int uni(Tre &a, Tre &b)
{
int ret = 0;
int toa = 1, tob = 1;
for(int i = 30; i >= 0; --i)
{
for(int j = 0; j < 4; ++j)
{
int pa = mov[j][0], pb = mov[j][1];
if(a.pre[a.trie[toa][pa]] && b.pre[b.trie[tob][pb]])
{
--a.pre[a.trie[toa][pa]], --b.pre[b.trie[tob][pb]];
if(j >= 2)
ret = ret + (1 << i);
toa = a.trie[toa][pa];
tob = b.trie[tob][pb];
break;
}
}
}
return ret;
}
int ans[MAXN];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
//freopen("d:\out.txt","w",stdout);
//freopen("in.txt","r",stdin);
cin >> t;
Tre a, b;
while(t--)
{
cin >> n;
a.init();
for(int i = 0, x; i < n; ++i)
{
cin >> x;
a.insert(x);
}
b.init();
for(int i = 0, x; i < n; ++i)
{
cin >> x;
b.insert(x);
}
fr(i, 0, n)
{
ans[i] = uni(a, b);
}
sort(ans, ans + n);
fr(i, 0, n)
{
if(i)
cout << ' ';
cout << ans[i];
}
cout << '\n';
}
return 0;
}