以下均学习与此博客https://blog.csdn.net/mmk27_word/article/details/98611040
-----------------------------------------------
题意:该你两个数组,问你这两个数组重新排列后a[i]^b[i]=c[i],让你按字典序最小输出c[i];
题解:对于一个给定数组和一个数,问这个数在这个数组中和某一个数的最大异或值/最小异或值,就是01字典树
- 这个题需要建两颗01字典树,查询的时候按照贪心的策略:
- 优先跑同一位置下相同的情况(即同一边),该位异或为0,其次在跑不同情况,加上改位的值(2^i)两颗字典树在同一位置,都是0和1两个分叉。
- 因为跑的时候不一定每次是最优的,结果需排列一下。
细节:每跑到一个节点都需改节点访问次数-1,因为val记录的是建树的时候这个节点被走过的次数,也就是说有多少个数字的二进制的这一位是相同的个数,走过就删除该数的意思,用过就不能再用了
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
struct node{
int nx[2];//连接两个子节点边的信息
int val;//点的信息
}T[2][maxn*32];
int tot[2];
int ans[maxn];
void init(){//初始化
tot[0]=tot[1]=1;
T[0][0].nx[0]=T[0][0].nx[1]=T[0][0].val=0;
T[1][0].nx[0]=T[1][0].nx[1]=T[1][0].val=0;
}
void insert(int x,int op){
int u=0;//根结点
for(int i=31;i>=0;i--){
int v=((x>>i)&1);//从高往低枚举当前位是0还是1
if(!T[op][u].nx[v]){//没有编号,创建结点
T[op][tot[op]].nx[0]=T[op][tot[op]].nx[1]=0;//初始化该结点的子结点
T[op][tot[op]].val=0;
T[op][u].nx[v]=tot[op]++; //将tot号作为新结点的编号
}
u=T[op][u].nx[v];//遍历到u的第V个儿子结点
T[op][u].val++;//访问次数+1
}
}
int query(){
int p0=0,p1=0;//首结点
int x=0;
for(int i=31;i>=0;i--){//优先走同一位置相同的情况
if(T[0][T[0][p0].nx[0]].val&&T[1][T[1][p1].nx[0]].val){
p0=T[0][p0].nx[0];
T[0][p0].val--;
p1=T[1][p1].nx[0];
T[1][p1].val--;
}else if(T[0][T[0][p0].nx[1]].val&&T[1][T[1][p1].nx[1]].val){
p0=T[0][p0].nx[1];
T[0][p0].val--;
p1=T[1][p1].nx[1];
T[1][p1].val--;
}else if(T[0][T[0][p0].nx[1]].val&&T[1][T[1][p1].nx[0]].val){
p0=T[0][p0].nx[1];
T[0][p0].val--;
p1=T[1][p1].nx[0];
T[1][p1].val--;
x+=(1<<i);//该位的(2^i)
}else if(T[0][T[0][p0].nx[0]].val&&T[1][T[1][p1].nx[1]].val){
p0=T[0][p0].nx[0];
T[0][p0].val--;
p1=T[1][p1].nx[1];
T[1][p1].val--;
x+=(1<<i);//该位的(2^i)
}
}
return x;
}
int main(){
std::ios::sync_with_stdio(false);
int t; cin>>t;
while(t--){
init();
int n; cin>>n;
for(int i=1;i<=n;i++){
int x; cin>>x;
insert(x,0);
}
for(int i=1;i<=n;i++){
int x; cin>>x;
insert(x,1);
}
for(int i=1;i<=n;i++){
ans[i]=query();
}
sort(ans+1,ans+n+1);
for(int i=1;i<=n;i++){
cout<<ans[i];
if(i<n) cout<<" ";
else cout<<endl;
}
}
return 0;
}