题意
做法
求最大异或的做法不用多说了,加入字典树,贪心即可,仁慈的出题人给了20分部分分.
关键是求最大与,最大或. 这里用的方法叫做
(我自己取的名字).
我们用一个
的数组标记
子集是否出现过.
那么当我们加入一个全集
的时候,我们随便去掉
某一位上的
,产生的就是它的一个子集.这时我们再递归将子集当做全集加入,就可以了.
在
之间每一个数只会加入一次,均摊复杂度
.
考虑回答最大与和最大或的询问.
从高位开始,如果是与,贪心寻找
的最高位,如果有,就直接将这一位加入答案.
没有这一位的数无论如何都不可能大过现在的答案,最高位必定要取.
现在
已经有了这一位,再往下寻找
为
的位,看看
有没有被标记过.
如果标记过,又是贪心选择这一位.
以此类推.
如果是或,反过来寻找
为
的位置即可.
AC代码如下.
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
int x=0,f=1;char c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return f?x:-x;
}
template <typename mitsuha>
inline bool read(mitsuha &x){
x=0;int f=1;char c=gc();
for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
if (!~c) return 0;
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return x=f?x:-x,1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return 0&pc(48);
if (x<0) x=-x,pc('-');
int bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
return 0;
}
inline char fuhao(){
char c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
const int yuzu=1<<20;
typedef int fuko[yuzu<<5];
int sz,q;
struct trie{
fuko ch[2],cnt;
void insert(int x){
int i,p,now=0;
for (i=21;~i;--i){
p=x>>i&1;
if (!ch[p][now]) ch[p][now]=++sz;
now=ch[p][now];
}
}
int query(int x){
/*最大异或不用解释*/
int i,p,now=0,llx=0;
for (i=21;~i;--i){
p=x>>i&1;
if (ch[!p][now]) now=ch[!p][now],llx|=1<<i;
else now=ch[p][now];
}
return llx;
}
}my_;
struct and_or{
fuko vis;
void insert(int x){
if (vis[x]) return; // 每个子集只加入一次.
vis[x]=1;
for (int i=19;~i;--i)
if (x>>i&1) insert(1<<i^x); // 加入x的每一个子集
}
int maxand(int x){
int i,llx=0;
for (i=19;~i;--i)
if (x>>i&1&&vis[1<<i^llx]) // x这一位上为1 并且ans+这一位的值被标记过.
llx^=1<<i;
return llx;
}
int maxor(int x){
int i,llx=0;
for (i=19;~i;--i)
if (!(x>>i&1)&&vis[1<<i^llx]) // x这一位上为0, ans+这一位的值被标记过.
llx^=1<<i;
return llx|x; // 最后不要忘了加上x.
}
}your;
int main(){
for (q=read();q--;){
int i,op=read(),x=read();
switch(op){
case 1:
/*一个my一个your是不是很有意思啊.*/
my_.insert(x);
your.insert(x);
break;
case 2:
write(my_.query(x)),p32;
write(your.maxand(x)),p32;
write(your.maxor(x)),pl;
break;
case 3:
write(my_.query(x)),pl;
break;
}
}
}