题意:
给你数组a和数组b,现在要求一个数组c,c[i]=a[i]^b[i],可以打乱数组a和数组b的顺序,问你c的字典序最小的构造方法是什么
题解:
按a,b构造两个字典树,每次贪心的走相同的边,如1,1或者0,0如果没有走相反的边,因为一个数必有一个唯一的数与它对应,同时字典序可以贪心的做,所以这个做法是没毛病的。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int tr[2][N*31][2],num[2][N*31];
int ans[N],cnt[2];
void update(int x,int u)
{
int rt=0;
for(int i=30;i>=0;i--)
{
if(!tr[u][rt][((x>>i)&1)])
tr[u][rt][((x>>i)&1)]=++cnt[u];
rt=tr[u][rt][((x>>i)&1)];
num[u][rt]++;
}
}
int query()
{
int rt0=0,rt1=0,ans=0;
for(int i=30;i>=0;i--)
{
if(tr[0][rt0][1]&&tr[1][rt1][1]&&num[0][tr[0][rt0][1]]&&num[1][tr[1][rt1][1]])
rt0=tr[0][rt0][1],rt1=tr[1][rt1][1],num[0][rt0]--,num[1][rt1]--;
else if(tr[0][rt0][0]&&tr[1][rt1][0]&&num[0][tr[0][rt0][0]]&&num[1][tr[1][rt1][0]])
rt0=tr[0][rt0][0],rt1=tr[1][rt1][0],num[0][rt0]--,num[1][rt1]--;
else if(tr[0][rt0][0]&&tr[1][rt1][1]&&num[0][tr[0][rt0][0]]&&num[1][tr[1][rt1][1]])
rt0=tr[0][rt0][0],rt1=tr[1][rt1][1],num[0][rt0]--,num[1][rt1]--,ans|=(1<<i);
else if(tr[0][rt0][1]&&tr[1][rt1][0]&&num[0][tr[0][rt0][1]]&&num[1][tr[1][rt1][0]])
rt0=tr[0][rt0][1],rt1=tr[1][rt1][0],num[0][rt0]--,num[1][rt1]--,ans|=(1<<i);
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,x;
cnt[0]=cnt[1]=0;
scanf("%d",&n);
for(int i=0;i<=n*31;i++)
{
tr[0][i][0]=tr[0][i][1]=tr[1][i][0]=tr[1][i][1]=0;
num[0][i]=num[1][i]=0;
}
for(int i=1;i<=n;i++)
scanf("%d",&x),update(x,0);
for(int i=1;i<=n;i++)
scanf("%d",&x),update(x,1);
for(int i=1;i<=n;i++)
ans[i]=query();
sort(ans+1,ans+1+n);
for(int i=1;i<=n;i++)
printf("%d%c",ans[i]," \n"[i==n]);
}
return 0;
}