题意:
中文
思路:
将数插入到01字典树中并记录子树的大小和子树中所有数的位信息。
查询时在字典树中搜索前K个即可。
注意数是可以重复的
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN=1e5+7;
int n,m,p;
int ls[MAXN*35]={0},rs[MAXN*35]={0},num[MAXN*35]={0},bit[MAXN*35][32]={0};
int cnt=0;
long long two[32];
int trans(int rt){
if(rt==0){
++cnt;
return cnt;
}
return rt;
}
void ini(){
for(int i=0;i<=cnt;i++){
ls[i]=rs[i]=num[i]=0;
for(int j=0;j<32;j++) bit[i][j]=0;
}
cnt=1;p=0;
}
void insert(int x){
int rt=1;
num[rt]++;
for(int i=31;i>=0;i--) bit[rt][i]+=(x>>i)%2;
for(int i=31;i>=0;i--){
int c=(x>>i)%2;
if(c==0){
ls[rt]=trans(ls[rt]);
rt=ls[rt];
num[rt]++;
for(int j=31;j>=0;j--) bit[rt][j]+=(x>>j)%2;
}else{
rs[rt]=trans(rs[rt]);
rt=rs[rt];
num[rt]++;
for(int j=31;j>=0;j--) bit[rt][j]+=(x>>j)%2;
}
}
}
long long query(int x,int k){
int rt=1;
long long ans=0;
for(int i=31;i>=0&&k;i--){
int c=(x>>i)%2;
if(c==0){
if(rs[rt]){
if(num[rs[rt]]<=k){
k-=num[rs[rt]];
for(int j=31;j>=0;j--){
int p=(x>>j)%2;
if(p==0){
ans+=bit[rs[rt]][j]*two[j];
}else{
ans+=(num[rs[rt]]-bit[rs[rt]][j])*two[j];
}
}
rt=ls[rt];
}else{
rt=rs[rt];
}
}else{
rt=ls[rt];
}
}else{
if(ls[rt]){
if(num[ls[rt]]<=k){
k-=num[ls[rt]];
for(int j=31;j>=0;j--){
int p=(x>>j)%2;
if(p==0){
ans+=bit[ls[rt]][j]*two[j];
}else{
ans+=(num[ls[rt]]-bit[ls[rt]][j])*two[j];
}
}
rt=rs[rt];
}else{
rt=ls[rt];
}
}else{
rt=rs[rt];
}
}
}
if(k){
for(int i=31;i>=0;i--){
int p=(x>>i)%2;
if((p==0&&bit[rt][i])||(p==1&&!bit[rt][i])){
ans+=k*two[i];
}
}
}
return ans;
}
int main(){
int T;
//freopen("data.in","r",stdin);
//freopen("out.txt","w",stdout);
two[0]=1;
for(int i=1;i<32;i++) two[i]=two[i-1]*2;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
ini();
for(int i=1;i<=n;i++){int x;scanf("%d",&x);
insert(x);
}
while(m--){int op,x;scanf("%d%d",&op,&x);
if(op==1){
p^=x;
}else{
printf("%lld\n",query(p,x));
}
}
}
}