经典题
由于异或等操作是不满足结合律的
所以按二进制位拆分
建四棵线段树就转化为区间取反和区间set
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline void read(int &x){
x=0;
int 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();
}
x*=f;
}
#define lc (p<<1)
#define rc (p<<1|1)
const int N=1e6+100;
int val[N];
struct Segment_Tree{
struct Node{
int lazy,len;
int sum;
}T[4][N<<2];
void Clear(){
memset(T,0,sizeof(T));
}
inline void PushUp(int p,int Id){
T[Id][p].len=T[Id][lc].len+T[Id][rc].len;
T[Id][p].sum=T[Id][lc].sum+T[Id][rc].sum;
}
inline void PushDown(int p,int Id){
int flag=0;
if(T[Id][p].sum==T[Id][p].len){
flag=1;
T[Id][lc].sum=T[Id][lc].len;
T[Id][rc].sum=T[Id][rc].len;
}
else{
if(T[Id][p].sum==0){
flag=1;
T[Id][lc].sum=T[Id][rc].sum=0;
}
}
if(T[Id][p].lazy){
T[Id][lc].lazy^=1;
T[Id][rc].lazy^=1;
if(!flag){
T[Id][lc].sum=T[Id][lc].len-T[Id][lc].sum;
T[Id][rc].sum=T[Id][rc].len-T[Id][rc].sum;
}
T[Id][p].lazy=0;
}
}
inline void build(int p,int l,int r,int Id){
T[Id][p].lazy=0;
if(l==r){
if(val[l]&(1<<Id)){
T[Id][p].sum=1;
}
else T[Id][p].sum=0;
T[Id][p].len=1;
return;
}
int mid=(l+r)/2;
build(lc,l,mid,Id);
build(rc,mid+1,r,Id);
PushUp(p,Id);
}
inline void Update_And(int p,int Dl,int Dr,int l,int r,int Id){//set 0
if(l<=Dl&&Dr<=r){
T[Id][p].sum=0;
T[Id][p].lazy=0;
return;
}
PushDown(p,Id);
int mid=(Dl+Dr)/2;
if(l<=mid)Update_And(lc,Dl,mid,l,r,Id);
if(mid< r)Update_And(rc,mid+1,Dr,l,r,Id);
PushUp(p,Id);
}
inline void Update_Or (int p,int Dl,int Dr,int l,int r,int Id){
if(l<=Dl&&Dr<=r){
T[Id][p].sum=T[Id][p].len;
T[Id][p].lazy=0;
return;
}
PushDown(p,Id);
int mid=(Dl+Dr)/2;
if(l<=mid)Update_Or(lc,Dl,mid,l,r,Id);
if(mid< r)Update_Or(rc,mid+1,Dr,l,r,Id);
PushUp(p,Id);
}
inline void Update_Xor(int p,int Dl,int Dr,int l,int r,int Id){
if(l<=Dl&&Dr<=r){
T[Id][p].sum=T[Id][p].len-T[Id][p].sum;
T[Id][p].lazy^=1;
return;
}
PushDown(p,Id);
int mid=(Dl+Dr)/2;
if(l<=mid)Update_Xor(lc,Dl,mid,l,r,Id);
if(mid< r)Update_Xor(rc,mid+1,Dr,l,r,Id);
PushUp(p,Id);
}
inline int Query(int p,int Dl,int Dr,int l,int r,int Id){
if(l<=Dl&&Dr<=r){
return T[Id][p].sum;
}
PushDown(p,Id);
int ans=0;
int mid=(Dl+Dr)/2;
if(l<=mid)ans+=Query(lc,Dl,mid,l,r,Id);
if(mid< r)ans+=Query(rc,mid+1,Dr,l,r,Id);
return ans;
}
}Tree;
int n,m;
int main(){
// freopen("FZU2105.in","r",stdin);
int Cas;
read(Cas);
while(Cas--){
Tree.Clear();
read(n);
read(m);
for(int i=1;i<=n;i++){
read(val[i]);
}
for(int i=0;i<4;i++)
Tree.build(1,1,n,i);
for(int i=1;i<=m;i++){
char opt[10];
scanf("%s",opt);
if(opt[0]=='S'){
int l,r;
read(l);
read(r);
l++;
r++;
int ans=0;
for(int i=0;i<4;i++){
int now=Tree.Query(1,1,n,l,r,i);
ans+=now*(1<<i);
}
cout<<ans<<'\n';
}
if(opt[0]=='X'){
int x,l,r;
read(x);
read(l);
read(r);
l++;
r++;
for(int i=0;i<4;i++){
if((1<<i)&x)Tree.Update_Xor(1,1,n,l,r,i);//,cout<<i<<" id "<<'\n';
}
}
if(opt[0]=='A'){
int x,l,r;
read(x);
read(l);
read(r);
l++;
r++;
for(int i=0;i<4;i++){
if(!((1<<i)&x))
Tree.Update_And(1,1,n,l,r,i);
}
}
if(opt[0]=='O'){
int x,l,r;
read(x);
read(l);
read(r);
l++;
r++;
for(int i=0;i<4;i++){
if((1<<i)&x)
Tree.Update_Or(1,1,n,l,r,i);
}
}
}
}
}