题面:https://www.luogu.org/problem/CF242E
因为XOR的lazy tag不可以叠加。
所以就弄得比较麻烦。
需要把每个数二进制拆分。
也把lazy tag二进制拆分。
0异或一个数还是那个数,1异或一个数就是取反。
所以遇见tag的第i位为1的时候就用总数减去现在的这位为1的个数。
然后所有都用线段树维护就行了。
代码如下:
#include<bits/stdc++.h> #define ll long long #define int long long using namespace std; const int maxn=100010; int n,a[maxn],f[maxn<<2][30],tg[maxn<<2]; inline void pushup(int p){ for(int i=0;i<21;i++) f[p][i]=f[(p<<1)][i]+f[(p<<1|1)][i]; return; } void build(int p,int l,int r){ if(l==r){ int now=a[l]; for(int i=0;i<21;i++) if((now>>i) & 1) f[p][i]++; return; } int mid=(l+r)>>1; build(p<<1,l,mid);build(p<<1|1,mid+1,r); pushup(p); } inline void pushdown(int p,int l,int r){ if(!tg[p]) return; tg[(p<<1)]^=tg[p];tg[(p<<1|1)]^=tg[p]; int mid=(l+r)>>1; for(int i=0;i<21;i++) if((tg[p]>>i)&1){ f[(p<<1)][i]=mid-l+1-f[(p<<1)][i]; f[(p<<1|1)][i]=r-mid-f[(p<<1|1)][i]; } tg[p]=0; return; } inline ll ask(int p,int l,int r,int x,int y){ if(x<=l && r<=y){ ll ans=0; for(int i=0;i<21;i++) ans+=f[p][i]*(1<<i); return ans; } pushdown(p,l,r); ll ans=0;int mid=(l+r)>>1; if(x<=mid) ans+=ask(p<<1,l,mid,x,y); if(y>mid) ans+=ask(p<<1|1,mid+1,r,x,y); return ans; } inline void change(int p,int l,int r,int x,int y,int d){ if(x<=l && r<=y){ tg[p]^=d; for(int i=0;i<21;i++) if((d>>i)&1) f[p][i]=r-l+1-f[p][i]; return; } pushdown(p,l,r); int mid=(l+r)>>1; if(x<=mid) change(p<<1,l,mid,x,y,d); if(y>mid) change(p<<1|1,mid+1,r,x,y,d); pushup(p); } signed main() { scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,1,n); int q;scanf("%lld",&q); while(q--){ int op;scanf("%lld",&op); if(op==1){ int l,r;scanf("%lld%lld",&l,&r); printf("%lld ",ask(1,1,n,l,r)); }else{ int l,r,x;scanf("%lld%lld%lld",&l,&r,&x); change(1,1,n,l,r,x); } } return 0; }