CF242E XOR on Segment
区间异或不好直接维护,于是我们考虑将所有数二进制分解。
我们把每一位单独提出来做,那么对于每一位,异或要么不变,要么取反,而位与位之间的操作是独立的!建一棵线段树维护每一位的信息,那么只要维护:
1.区间取反(0变1,1变0)
2.区间求和
即可。这个利用线段树+标记能够很轻松的实现。
所以总复杂度为(O(nk log n)),其中k为二进制的位数,这里(k ≤20)。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=400005;
inline 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 f*x;
}
int n,m,a[N];
ll val[21][N];
bool tag[21][N];
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
void build(int l,int r,int p) {
if(l==r) {
for(int i=0;i<=20;i++)
if(a[l]&(1<<i))
val[i][p]=1;
return;
}
build(l,mid,ls);
build(mid+1,r,rs);
for(int i=0;i<=20;i++)
val[i][p]=val[i][ls]+val[i][rs];
}
void pushdw(int p,int l,int r,int i) {
tag[i][ls]^=tag[i][p];
tag[i][rs]^=tag[i][p];
if(!tag[i][p]) return;
val[i][ls]=mid-l+1-val[i][ls];
val[i][rs]=r-mid-val[i][rs];
tag[i][p]=0;
}
void modify(int l,int r,int L,int R,int i,int p) {
if(L<=l&&r<=R) {
val[i][p]=r-l+1-val[i][p];
tag[i][p]^=1;
return;
}
pushdw(p,l,r,i);
if(L<=mid) modify(l,mid,L,R,i,ls);
if(R>mid) modify(mid+1,r,L,R,i,rs);
val[i][p]=val[i][ls]+val[i][rs];
}
ll query(int l,int r,int L,int R,int p) {
if(L<=l&&r<=R) {
ll ans=0;
for(int i=0;i<=20;i++)
ans+=(val[i][p]<<i);
return ans;
}
for(int i=0;i<=20;i++)
pushdw(p,l,r,i);
ll ans=0;
if(L<=mid) ans+=query(l,mid,L,R,ls);
if(R>mid) ans+=query(mid+1,r,L,R,rs);
return ans;
}
int main() {
n=read();
for(int i=1;i<=n;i++) a[i]=read();
build(1,n,1);
m=read();
while(m--) {
int op=read(),l=read(),r=read();
if(op==1) {
printf("%lld
",query(1,n,l,r,1));
} else {
int x=read();
for(int i=0;i<=20;i++)
if(x&(1<<i))
modify(1,n,l,r,i,1);
}
}
return 0;
}