链接 http://acdream.info/problem?pid=1063
题目是中文,题意我就不赘述了。
题目中有3中操作,一个是加入一个数加入树上,还有2个查询,给你一个X,查找树中的一个Y使得 X^Y 最大或最小。
从数据范围 上看,需要 log 级别的速度。
首先 异或,2个数异或的算法是2进制的每一位相同为0,不同为1. 那么是不是在一堆数中找一个与X异或的最大,那么对于这个数每一位尽量都使得不与X的2进制每一位相同。
那么熟悉一点的就可以想到字典树。树的节点只有0,1 ,当你插入一个数的时候,就相当于把这个数转换为2进制 ,由于数的范围是INT,那么 只需要32层左右就能插入一个数。
当然,由于需要从最高位开始判断,才有那种贪心优先顺序的正确性(请仔细理解),所以需要用最上面的节点表示最高位,最下面的叶子是最低位。
最后需要注意的问题是 字典树的 节点清除操作。需要递归才行。
AC代码如下
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using
namespace
std;
int
c[35];
struct
node
{
node *next[2];//节点个数表示 01.
node()
{
memset
(next,NULL,
sizeof
(next));//初始化
}
}root;
void
init(node *p)//递归清空节点。
{
if
(p->next[0]!=NULL)
{
init(p->next[0]);
delete
p->next[0];
}
if
(p->next[1]!=NULL)
{
init(p->next[1]);
delete
p->next[1];
}
}
void
Insert(node *root)
{
node *p=root;
int
i;
for
(i=30;i>=0;i--)
{
int
x=c[i];
if
(p->next[x]==NULL)
{
p->next[x]=
new
node;
}
p=p->next[x];
}
}
int
querymax(node *root,
int
sum)//查询最大异或值,
{
int
i;
int
sumy=0;
node *p=root;
for
(i=30;i>=0;i--)
{
int
x=c[i];
if
(p->next[1-x]!=NULL)
{
p=p->next[1-x];
sumy=sumy*2+1-x;
}
else
if
(p->next[x]!=NULL)
{
p=p->next[x];
sumy=sumy*2+x;
}
else
{
break
;
}
}
return
sumy^sum;
}
int
querymin(node *root,
int
sum)//最小异或值
{
int
i;
int
sumy=0;
node *p=root;
for
(i=30;i>=0;i--)
{
int
x=c[i];
if
(p->next[x]!=NULL)
{
p=p->next[x];
sumy=sumy*2+x;
}
else
if
(p->next[1-x]!=NULL)
{
p=p->next[1-x];
sumy=sumy*2+(1-x);
}
else
{
break
;
}
}
return
sumy^sum;
}
int
main()
{
int
n;
int
T;
scanf
(
"%d"
,&T);
while
(T--)
{
scanf
(
"%d"
,&n);
init(&root);
memset
(root.next,NULL,
sizeof
(root.next));
int
x;
char
s[15];
while
(n--)
{
scanf
(
"%s %d"
,s,&x);
int
tmp=x;
int
len=0;
memset
(c,0,
sizeof
(c));
while
(tmp)
{
c[len++]=tmp%2;
tmp=tmp/2;
}
if
(s[0]==
'i'
)
Insert(&root);
else
if
(s[2]==
'i'
)
printf
(
"%d\n"
,querymin(&root,x));
else
if
(s[2]==
'a'
)
printf
(
"%d\n"
,querymax(&root,x));
}
}
return
0;
}