YMH在一个月之前写了这个题
当时我不知所云
现在看来数据结构水平还是在提升的。QwQ
最先想的线段树二进制拆分
但是似乎不行,因为排序不行
这个时候可持久化字典树横空出世:他里面的数本身有序
有可以支持异或(交换左右儿子就好了)
然后对于还没有排序的
维护二进制前缀和,暴力算是log的
然后就完了
#include<bits/stdc++.h>
using namespace std;
typedef int INT;
#define int long long
inline void read(int &x){
x=0;
char ch=getchar();
int f=1;
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
int del;
const int N=2e5+100;
struct Trie{
int ch[N*31][2];
int sum[N*31][31];
int siz[N*31];
int Lazy;
int rt;
int cnt;
Trie(){
rt=1;
cnt=1;
}
int Get_siz(){
return siz[ch[rt][0]]+siz[ch[rt][1]];
}
int Get_Num(int Id){
int ret=0;
for(int i=0;i<=30;i++){
if(del&(1<<i)){
ret+=(1<<i)*(siz[Id]-sum[Id][i]);
}
else ret+=(1<<i)*sum[Id][i];
}
return ret;
}
void Insert(int x){
int now=rt;
for(int i=30;i>=0;i--){
int Id=((x>>i)&1);
if(!ch[now][Id]){
ch[now][Id]=++cnt;
}
now=ch[now][Id];
for(int j=30;j>=0;j--){
if(x&(1<<j)){
sum[now][j]++;
}
}
siz[now]++;
}
}
int Query(int k){
if(!k)return 0;
int now=rt;
int ans=0;
for(int i=30;i>=0;i--){
int l=0;
int r=1;
if(Lazy&(1<<i)){
swap(l,r);
}
if(siz[ch[now][l]]<k){
k-=siz[ch[now][l]];
ans+=Get_Num(ch[now][l]);
now=ch[now][r];
}
else now=ch[now][l];
}
ans+=Get_Num(now)/siz[now]*k;
return ans;
}
}T;
struct presum{
int len;
int sum[N][31];
int a[N];
void Insert(int x){
len++;
a[len]=x;
for(int i=30;i>=0;i--){
int now=((x>>i)&1);
sum[len][i]=sum[len-1][i]+now;
}
}
int Query(int x){
int ans=0;
for(int i=0;i<=30;i++){
if((del>>i)&1)
ans+=(1<<i)*(x-sum[x][i]);
else ans+=(1<<i)*sum[x][i];
}
return ans;
}
void Change(){
for(int i=1;i<=len;i++){
T.Insert(a[i]);
}
T.Lazy=del;
len=0;
}
}Arr;
int n,m;
int A[N];
int Query_Sum(int x){
if(x<=T.Get_siz()){
return T.Query(x);
}
else{
return T.Query(T.Get_siz())+Arr.Query(x-T.Get_siz());
}
}
INT main(){
// freopen("test.in","r",stdin);
read(n);
for(int i=1;i<=n;i++){
read(A[i]);
}
for(int i=1;i<=n;i++){
Arr.Insert(A[i]);
}
read(m);
for(int i=1;i<=m;i++){
int opt;
read(opt);
if(opt==1){
n++;
read(A[n]);
A[n]^=del;
Arr.Insert(A[n]);
}
if(opt==2){
int l,r;
read(l);
read(r);
cout<<Query_Sum(r)-Query_Sum(l-1)<<'\n';
}
if(opt==3){
int x;
read(x);
del^=x;
}
if(opt==4){
Arr.Change();
}
}
}