原题链接:acwing143.最大异或对
算法:(Tire字典树)
思路:
1.由于时间与空间的限制我们显然不可能暴力得到答案,而且万一有重复的数字,我们没必要再用新的空间去储存,所以我们要利用原先已经用过的空间来储存;
2.通过题目的异或我们很容易想到01,甚至二叉树,不如将每个数字转化为01比特串来用Tire树高效存储和查询
具体看代码实现
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
//因为答案要最大,所以异或的时候要从30位开始,异或出最多1,答案自然最大了
#define fir for (int k=30;k>=0;k--) ///Ai范围为正数int内,所以只要考虑30~0位,第31位为符号位,由题意都为正数,所以符号位都为0,最后答案异或出来都为正数,所以无需考虑第31位
int tire[N*31][2]; //定义一个tire数,N==10^5,一个Ai拆分为一个01比特串,而且只考虑30~0位,所以节点最大个数乘以31就够了,每个节点的儿子节点只有两种可能0或者1,所以后面大小为2
int idx; //idx为0时,为根节点,也为空节点,其他节点从1开始计
void insert(int x)
{
int p=0; //根节点开始走
fir
{
int u=x>>k&1; //取出x在K位置的bit
if (!tire[p][u]) tire[p][u]=++idx; //如果没有儿子节点,就创建一个儿子节点,注意是++idx
p=tire[p][u]; //往儿子节点走
}
}
int Search(int x)
{
int p=0,res=0;
fir
{
int u=x>>k&1;
if (tire[p][u^1]) //一旦儿子节点里面有能异或出为1的,就异或走路
{
p=tire[p][u^1];
res|=1<<k; //往res的K位置添加1
}
else p=tire[p][u]; //不能异或出1,就走原先的路
}
return res; //得到x与原先储存好的所有数的异或最大值
}
int main ()
{
int n; cin>>n;
int ans=0;
while (n--)
{
int x; cin>>x;
insert(x);
ans=max(ans,Search(x)); //可以边插入边更新答案,因为每一次都能得到插入一个新的x之后的最大值
}
cout<<ans;
return 0;
}