题目大意
一些数,可以修改,每次询问全部加x并与y作and后的和。
一眼题
显然看到位运算就分位做。
在第k位,所有数都模2^k,然后用数据结构维护。
然后只看y有1的位。
分类讨论数的第k位是0/1,x的第k位是0/1,然后用数据结构求出此时最终加上x后第k位是1的个数,就能统计答案。
这个数据结构推荐使用树状数组。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
int tree[20][1050000];
int a[maxn],st[100];
int i,j,k,l,r,s,t,n,m,tot,top,id,d;
bool czy;
ll ans;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void write(ll x){
if (!x){
putchar('0');
putchar('\n');
return;
}
top=0;
while (x){
st[++top]=x%10;
x/=10;
}
while (top){
putchar(st[top]+'0');
top--;
}
putchar('\n');
}
int lowbit(int x){
return x&-x;
}
void insert(int x,int y,int v){
if (!y){
tree[x][y]+=v;
return;
}
while (y<=1048576){
tree[x][y]+=v;
y+=lowbit(y);
}
}
int getans(int x,int y){
if (y<0) return 0;
int t=tree[x][0];
while (y){
t+=tree[x][y];
y-=lowbit(y);
}
return t;
}
int get(int k,int x){
return n-getans(k,x-1);
}
int query(int k,int x){
return getans(k,x);
}
int main(){
freopen("t3.in","r",stdin);freopen("t3.out","w",stdout);
n=read();m=read();
fo(i,1,n) a[i]=read();
fo(i,1,n){
t=0;
fo(j,0,19){
t+=(1<<j)*((a[i]/(1<<j))%2);
insert(j,t,1);
}
}
fo(i,1,m){
t=read();
if (t==1){
j=read();k=read();
r=s=0;
fo(l,0,19){
r+=(1<<l)*((a[j]/(1<<l))%2);
s+=(1<<l)*((k/(1<<l))%2);
//change(l,r,s);
insert(l,r,-1);
insert(l,s,1);
}
a[j]=k;
}
else{
d=read();s=read();
ans=t=0;
fo(k,0,19){
/*t+=(1<<k)*((d/(1<<k))%2);
if ((s/(1<<k))%2==0) continue;
j=get(k,(1<<(k+1))-1-t)-get(k,(1<<k)-1-t);
ans+=(ll)(1<<k)*j;*/
if ((s/(1<<k))%2==0){
t+=(1<<k)*((d/(1<<k))%2);
continue;
}
j=get(k,(1<<(k+1))-t);
if ((d/(1<<k))%2==1) ans+=(ll)(1<<k)*j;
else ans+=(ll)(1<<k)*(get(k,1<<k)-j);
j=query(k,(1<<k)-t-1);
if ((d/(1<<k))%2==1) ans+=(ll)(1<<k)*j;
else ans+=(ll)(1<<k)*(query(k,(1<<k)-1)-j);
t+=(1<<k)*((d/(1<<k))%2);
}
write(ans);
}
}
}