给一列数,可以让第l到r个数同时与、或、异或上某个数,或者求第l到r个数的和
数据范围:总共10^6个数,10^5次操作,每个数的大小在[0,16)内
把每个数都按照二进制分成4位,建立4棵线段树,线段树上有置零(与操作),置一(或操作),取反(异或操作)三种操作,有求和查询
#include <cstring>
#include <cstdio>
struct Node {
int l,r,sum,lazy;
Node *ls,*rs;
Node () {}
Node (int ll,int rr) {
l=ll;r=rr;
sum=0;lazy=0;
ls=rs=NULL;
}
void *operator new (size_t,void *p) {
return p;
}
void getLazy(int x) {
if (x==0) return;
else if (lazy==0) lazy=x;
else if (x==1) lazy=1;
else if (x==2) lazy=2;
else if (lazy==1) lazy=2;
else if (lazy==2) lazy=1;
else lazy=0;
}
void down() {
if (ls!=NULL) ls->getLazy(lazy);
if (rs!=NULL) rs->getLazy(lazy);
if (lazy==1) sum=r-l+1;
else if (lazy==2) sum=0;
else if (lazy==3) sum=r-l+1-sum;
lazy=0;
}
};
struct SegTree {
Node a[2100000];
Node *root,*las,*tmp;
void clear(int x[],int n) {
las=a;
for (int i=0;i<n;i++) {
tmp=new(las++)Node(i,i);
tmp->sum=x[i];
}
root=makeTree(0,n-1);
}
Node *makeTree(int l,int r) {
if (l==r) return a+l;
Node *ans=new(las++)Node(l,r);
int t=(l+r)/2;
ans->ls=makeTree(l,t);
ans->rs=makeTree(t+1,r);
ans->sum=ans->ls->sum+ans->rs->sum;
return ans;
}
void set(Node *from,int l,int r,int opt) {
if (from->l==l&&from->r==r) {
from->getLazy(opt);
return;
}
from->down();
int t=(from->l+from->r)/2;
if (t>=r) set(from->ls,l,r,opt);
else if (t<l) set(from->rs,l,r,opt);
else {
set(from->ls,l,t,opt);
set(from->rs,t+1,r,opt);
}
from->ls->down();
from->rs->down();
from->sum=from->ls->sum+from->rs->sum;
}
int get(Node *from,int l,int r) {
from->down();
if (from->l==l&&from->r==r) return from->sum;
int t=(from->l+from->r)/2;
if (t>=r) return get(from->ls,l,r);
else if (t<l) return get(from->rs,l,r);
else return get(from->ls,l,t)+get(from->rs,t+1,r);
}
};
int n,m;
SegTree a[4];
int b[1000000];
int c[1000000];
int main() {
int t,i,j,opn,l,r,ans;
char s[10];
scanf("%d",&t);
while (t--) {
scanf("%d%d",&n,&m);
for (i=0;i<n;i++) scanf("%d",&b[i]);
for (i=0;i<4;i++) {
for (j=0;j<n;j++) c[j]=((b[j]&(1<<i))!=0);
a[i].clear(c,n);
}
for (i=0;i<m;i++) {
scanf("%s",s);
if (s[0]=='A') {
scanf("%d%d%d",&opn,&l,&r);
for (j=0;j<4;j++) {
if ((opn&(1<<j))==0) a[j].set(a[j].root,l,r,2);
}
} else if (s[0]=='O') {
scanf("%d%d%d",&opn,&l,&r);
for (j=0;j<4;j++) {
if ((opn&(1<<j))!=0) a[j].set(a[j].root,l,r,1);
}
} else if (s[0]=='X') {
scanf("%d%d%d",&opn,&l,&r);
for (j=0;j<4;j++) {
if ((opn&(1<<j))!=0) a[j].set(a[j].root,l,r,3);
}
} else {
scanf("%d%d",&l,&r);
ans=0;
for (j=0;j<4;j++) {
//printf("%d ",a[j].get(a[j].root,l,r));
ans+=a[j].get(a[j].root,l,r)*(1<<j);
}
//printf("\n");
printf("%d\n",ans);
}
}
}
return 0;
}