题目链接:http://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1783
题目大意:先输入n,然后保存这n个数字,然后输入m,表示m次操作。有两种操作,第一种是保存输入的一个数字,第二种是输入一个数字,找保存的数字和这个数字异或和最大的数字,输出这个保存的数字。(n,m<=100000 输入的数字<=1000000)
前言:讲这道题前先浅谈一下字典树。如果有n个小写字母,然后有m个查询,每个查询包含一个字母,问这个字母在n个字母中出现几次,怎样高效的查找?
1.for找n遍,复杂度O(n*m)
2.vis[c-'a']++,hash表存字母出现的个数,复杂度O(m)
换一个问题,如果有n个字符串,然后有m个查询,每个查询包含一个字符串,问这个字符串在n个字符串中出现几次,怎样高效的查找?
0.for 循环。
1.用map <string,int>,插入复杂度O(logn),查找复杂度O(mlogn) ,map找字符串是否匹配还要一个个去比较字符是否相等
2.类似上面的第二个方法,用hash表去找,但是要找一遍单词的每个字符是否在hash表里,相当于多次进行第一个问题的操作。复杂度明显比map低很多。所以问题就在于怎么去找,在第一个字符一样的前提,怎么去找下一个字符。
字典树的本质就是被查询的对象需要依次进行多次的hash查找,并且上一次的查找结果会影响到下一次的查找
什么时候用到字典树?查询的对象需要依次进行hash查找的时候。
比如:给定N个单词,查询N个单词中前缀为"abc"的是否存在,用hash去找a是否存在,a存在的话去找b,在去找c,这就是多次去找。前缀abc第一次去找a,找到后去x位置找b,而如果前缀是"cbb"的话,第一次找c,然后从y位置去找b,x和y的位置必然是不同,因为位置相同的话表示他们两个之前找的字符必然完全相同。这就是上一次的查找结果会影响到下次。
这里给个学习字典树的链接:https://www.cnblogs.com/TheRoadToTheGold/p/6290732.html
下面给出这道题的思路:
一般算法复杂度O(n*m) 在这里不赘述。下面讲AC解法。
要求出异或后的值最大,异或表示相同为0,不同为1。什么情况下值会最大?越高位出现0^1,则值越大。所以说把查询的值转成二进制,从高位开始,如果查询的数是0,则所有被查询的高位有没有1,是1则找0。然后在找下一位。有没有想到什么?这不就是字典树的本质:查询的对象需要依次进行多次的hash查找。
下面给出代码:
#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;
struct node
{
int l,r,ID;
}tree[(1<<22)+10];
int sum,bit[20];
void Create(int num)
{
int pos=0,next;
for(int j=19;j>=0;j--)
{
if(bit[j])
{
if(tree[pos].r)
{
next=tree[pos].r;
pos=next;
}
else
{
tree[pos].r=++sum;
next=tree[pos].r;
pos=next;
}
bit[j]=0;
}
else
{
if(tree[pos].l)
{
next=tree[pos].l;
pos=next;
}
else
{
tree[pos].l=++sum;
next=tree[pos].l;
pos=next;
}
}
}
tree[pos].ID=num;
return ;
}
int main(int argc, char *argv[])
{
int m,op,c,n,num,ct,tnum;
while(cin>>n)
{
sum=0;
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++)
{
ct=0;
scanf("%d",&num);
tnum=num;
while(num)
{
if(num%2==1) bit[ct++]=1;
else bit[ct++]=0;
num/=2;
}
Create(tnum);
}
cin>>m;
while(m--)
{
scanf("%d %d",&op,&c);
ct=0;
tnum=c;
while(c)
{
if(c%2==1) bit[ct++]=1;
else bit[ct++]=0;
c/=2;
}
if(op)
{
int pos=0,next;
for(int i=19;i>=0;i--)
{
if(bit[i]==0)
{
if(tree[pos].r)
{
next=tree[pos].r;
pos=next;
}
else
{
next=tree[pos].l;
pos=next;
}
}
else
{
if(tree[pos].l)
{
next=tree[pos].l;
pos=next;
}
else
{
next=tree[pos].r;
pos=next;
}
bit[i]=0;
}
}
printf("%d\n",tree[pos].ID);
}
else
{
Create(tnum);
}
}
}
return 0;
}