版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/81908911
描述
有q次操作,每次操作是以下两种:
- 加入一个数到集合中
- 查询,查询当前数字与集合中的数字的最大异或值,最大and值,最大or值
输入
第一行1个正整数Q表示操作次数
接下来Q行,每行2个数字,第一个数字是操作序号OP(1,2),第二个数字是X表示操作的数字
输出
输出查询次数行,每行3个整数,空格隔开,分别表示最大异或值,最大and值,最大or值
样例输入
【输入样例1】
5
1 2
1 3
2 4
1 5
2 7
【输出样例1】
7 0 7
5 5 7
【样例解释1】
询问4时,已插入2、3,最大异或值为4^3=7,最大and值为4&3或4&2=0,最大or值为4|3=7
询问7时,已插入2、3、5,最大异或值为7^2=5,最大and值为7&5=5,最大or值为7|2=7|3=7|5=7
【输入样例2】
10
1 194570
1 202332
1 802413
2 234800
1 1011194
2 1021030
2 715144
2 720841
1 7684
2 85165
【输出样例2】
1026909 201744 1032061
879724 984162 1048062
655316 682376 1043962
649621 683464 1048571
926039 85160 1011199
BB:
做这道题的心路历程也真的是绝了。。。
先是隐约想出了and和or的正解写法,却不知道如何处理xor。。。
后来写了个 ,xor调过了,and和or又调不出来。。。
最后交了一个暴力。。。
解析:
相信xor大家应该都会。。。就是 上面的贪心操作。
对于and,我们思考一下,当前数已经为0的位我们无能为力了对吧,所以我们只能在原数为1的位置上尽量多放1,而且越靠前越好。
那么,不就只需要维护一下有哪些位在同一个数中出现过就行了吗?
对于or,作类似考虑。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define st static
inline
ll getint(){
st ll num;
st char c;
while(!isdigit(c=gc()));
for(num=0;isdigit(c);c=gc())num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline
void outint(ll a){
st char ch[23];
if(!a)pc('0');
while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
while(ch[0])pc(ch[ch[0]--]);
}
cs int M=(1<<21);
bool b[5000001];
bool mark[1<<22];
inline
void marksubset(int k){
mark[k]=true;
for(int re i=0;i<=19;++i){
if((k&(1<<i))&&!mark[k^(1<<i)])marksubset(k^(1<<i));
}
}
inline
void buildtrie(int k){
k+=M;
while(k){
if(b[k])break;
b[k]=true,k>>=1;
}
}
inline
void ins(int k){
if(!mark[k]){
marksubset(k);
}
buildtrie(k);
}
inline
int queryxor(int k){
int now=1;
for(int re i=20;i>=0;--i){
if(b[now<<1]==true&&b[now<<1|1]==false){
now=now<<1;
}
else if(b[now<<1]==false&&b[now<<1|1]==true){
now=now<<1|1;
k^=(1<<i);
}
else if(b[now<<1]==true&&b[now<<1|1]==true){
if((k&(1<<i))==0){
now=now<<1|1;
k^=(1<<i);
}
else{
now=now<<1;
}
}
}
return k;
}
inline
int queryand(int k){
int now=0;
for(int re i=20;~i;--i){
if((k&(1<<i))&&mark[now|(1<<i)])now|=(1<<i);
}
return now&k;
}
inline
int queryor(int k){
int now=0;
for(int re i=20;~i;--i){
if(!(k&(1<<i))&&mark[now|(1<<i)])now|=(1<<i);
}
return now|k;
}
int Q;
int main(){
Q=getint();
while(Q--){
int op=getint();
int num=getint();
switch(op){
case 1:{
ins(num);
break;
}
case 2:{
outint(queryxor(num)),pc(' ');
outint(queryand(num)),pc(' ');
outint(queryor(num)),pc('\n');
break;
}
}
}
return 0;
}