题意:
第一行给你一个n
第二行给你n个数字 分别是a[1],a[2]…a[n]。
第三行给你n个数字 分别是b[1],b[2]…b[n]。
问:第三行的序列可自由排列,要求排列之后的顺序
a[1] ^ b[1], a[2] ^ b[2]…a[n]^b[n]的字典序最小。
题解:
因为b数组可以自由排列,那么我们把b数组先生成一个字典序。
要想字典序最小,那么根据贪心的思想,我们a[1]要与b中的某个数异或后值最小。
那么我们再遍历一遍a数组每次找出当前能组合的最小值。
因为每次组合后,我们需要删除b中一个元素,那么b已经是字典树了,怎么删?
我们用一个size数组来记录这个数出现的次数,和一个fa数组记录当前结点的父亲结点。
当size[node]=0的时候,这个数字也就没了,就该删除这个结点了。(因为可能会出现重复数组)
递归往上删除,如果当前节点删除,他的父节点只有它一个孩子,那么该父节点也需要删除,重复操作即可!
代码:
/*Keep on going Never give up*/
//#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
//#define int long long
#define endl '\n'
#define Accepted 0
#define AK main()
#define I_can signed
using namespace std;
const int maxn =1e7+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
using namespace std;
int trie[maxn][2],sz[maxn],fa[maxn];
int cnt;
int a[500000];
void ins(int x){
int node=0;
for(int i=31;i>=0;i--){
int t=(x>>i)&1;
if(!trie[node][t]){
trie[node][t]=++cnt;
fa[cnt]=node;
}
node=trie[node][t];
}
sz[node]++;
}
int quer(int x){
int res=0,node=0;
for(int i=31;i>=0;i--){
int t=(x>>i)&1;
if(trie[node][t]){
node=trie[node][t];
}
else{
node=trie[node][t^1];
res|=(1<<i);
}
}
if((--sz[node])==0){
while(node){
int f=fa[node],b;
if(trie[f][1]==node) b=1;
else b=0;
trie[f][b] = 0;
trie[node][b]=0;
if(trie[f][b^1]) break;
node=f;
}
}
return res;
}
signed main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
//ins(a[i]);
}
for(int i=0;i<n;i++){
int x;
cin>>x;
ins(x);
}
for(int i=0;i<n;i++){
cout<<quer(a[i])<<" ";
}
return 0;
}