給你一個序列,請完成以下操作:
- 插入一個數。
- 刪除一個數。
- 所有數,對取模。
- 所有數異或上。
思考一下加法的實質。
把一個數拆成低位到高位的形式,,那麼我們實際上就是要找到一個最小的,使得,然後把這些數全部取反,讓,這就完成了一個加法。如果說,那就取反,不用考慮,順便完成了取模。
至於異或,我們就只需要搞一個異或標記就可以,完全不用考慮。
那麼插入和刪除呢??沒錯。怎麼搞加法?直接記一個數爲,讓這個數異或上當前異或標記,然後在上面檢索它,走到的點把左右兒子分別交換,這樣就完成了加法。
#include <bits/stdc++.h>
#define regi register int
int n,m,tot,cnt,Xor;
int temp[10000001];
int A[10000001];
struct Trie{
int end;
int s[2];
}t[10000001];
inline int read(){
int r=0,w=0,c;
for(;!isdigit(c=getchar());r=c);
for(w=c^48;isdigit(c=getchar());
w=w*10+(c^48));
return r^45?w:-w;
}
inline void insert(int x){
int now=0;
for(regi j=0;j<=29;++j){
int to=(x>>j)&1;
if(!t[now].s[to])
t[now].s[to]=++tot;
now=t[now].s[to];
}
t[now].end++;
}
inline void zyinsert(int x){
int now=0;
for(regi j=0;j<=29;++j){
int to=(x>>j)&1;
now=t[now].s[to];
}
t[now].end--;
}
inline void rotate(int x){
int now=0;
int tail=0;
for(regi i=0;i<=29;++i){
temp[++tail]=now;
int to=(x>>i)&1;
now=t[now].s[to];
if(!now)
break;
}
for(regi i=1;i<=tail;++i)
std::swap(t[temp[i]].s[0],t[temp[i]].s[1]);
}
void Put(int x,int val,int cs){
if(cs==30){
for(regi i=1;i<=t[x].end;++i)
A[++cnt]=val^Xor;
}
if(t[x].s[0])
Put(t[x].s[0],val,cs+1);
if(t[x].s[1])
Put(t[x].s[1],val+(1<<cs),cs+1);
}
main(){
n=read(),m=read();
for(regi i=1,x;i<=n;++i){
x=read();
insert(x);
}
for(regi i=1,op,x;i<=m;++i){
op=read();
op!=3?x=read():0;
if(op==1)
insert(x^Xor);
if(op==2)
zyinsert(x^Xor);
if(op==3)
rotate((((1<<30)-1)^Xor));
if(op==4)
Xor^=x;
}
Put(0,0,0);
std::sort(A+1,A+cnt+1);
for(regi i=1;i<=cnt;++i)
printf("%d ",A[i]);
return 0;
}