//参考了别人的代码,又改进了一下,只用一个数组进行标记,理解了其实也是很简单的……
#include <stdio.h>
#include <string.h>
const int N = 1000005;
int c, res, a[N*4][4], flag[N*4][4], len[N*4];
void pushDown( int rt )
{
int ls = 2 * rt; int rs = ls | 1;
for( int i = 0; i < 4; ++i )
{
if( flag[rt][i] == -1 ) continue;
if( flag[rt][i] == 0 || flag[rt][i] == 1 )
{
a[ls][i] = ( flag[ls][i] = flag[rt][i] ) * len[ls];
a[rs][i] = ( flag[rs][i] = flag[rt][i] ) * len[rs];
flag[rt][i] = -1;
}
else if( flag[rt][i] == 3 )
{
flag[rt][i] = -1;
}
else
{
a[ls][i] = len[ls] - a[ls][i];
if( flag[ls][i] == -1 ) flag[ls][i] = 2;
else flag[ls][i] ^= 1;
a[rs][i] = len[rs] - a[rs][i];
if( flag[rs][i] == -1 ) flag[rs][i] = 2;
else flag[rs][i] ^= 1;
flag[rt][i] = -1;
}
}
}
void pushUp( int rt )
{
int ls = 2 * rt; int rs = ls | 1;
for( int i = 0; i < 4; ++i )
a[rt][i] = a[ls][i] + a[rs][i];
}
void build( int l, int r, int rt )
{
len[rt] = r - l + 1;
if( l == r )
{
scanf("%d", &c);
for( int i = 0; i < 4; ++i )
a[rt][i] = ( 1 & (c>>i) );
}
else
{
int mid = ( l + r ) / 2;
build(l, mid, 2 * rt);
build(mid + 1, r, 2 * rt + 1);
pushUp( rt );
}
}
void OR( int rt, int opn )
{
for( int i = 0; i < 4; ++i )
{
if( !( (opn>>i) & 1 ) ) continue;
flag[rt][i] = 1;
a[rt][i] = len[rt];
}
}
void ADD( int rt, int opn )
{
for( int i = 0; i < 4; ++i )
{
if( (opn>>i) & 1 ) continue;
flag[rt][i] = 0;
a[rt][i] = 0;
}
}
void XOR( int rt, int opn )
{
for( int i = 0; i < 4; ++i )
{
if( !( (opn>>i) & 1 ) ) continue;
if( flag[rt][i] == -1 ) flag[rt][i] = 2;
else flag[rt][i] ^= 1;
a[rt][i] = len[rt] - a[rt][i];
}
}
void query( int l, int r, int rt, int aa, int bb )
{
if( aa <= l && r <= bb )
{
res = res + a[rt][0] + a[rt][1] * 2 + a[rt][2] * 4 + a[rt][3] * 8;
return;
}
pushDown( rt );
int mid = ( l + r ) / 2;
int ls = 2 * rt; int rs = ls | 1;
if( mid >= aa ) query( l, mid, ls, aa, bb );
if( mid < bb ) query( mid + 1, r, rs, aa, bb );
}
void update( int l, int r, int rt, int aa, int bb, int opn, int f )
{
if( aa <= l && r <= bb )
{
switch( f )
{
case 0: OR( rt, opn ); break;
case 1: ADD( rt, opn ); break;
case 2: XOR( rt, opn ); break;
}
return;
}
pushDown( rt );
int mid = ( l + r ) / 2;
int ls = 2 * rt; int rs = ls | 1;
if( mid >= aa ) update( l, mid, ls, aa, bb, opn, f );
if( mid < bb ) update( mid + 1, r, rs, aa, bb, opn, f );
pushUp( rt );
}
int main()
{
int t, n, m, aa, bb, opn; char cmd[4];
scanf("%d", &t);
while( t-- )
{
memset( flag, -1, sizeof(flag) );
scanf("%d%d", &n, &m);
build(0, n-1, 1);
while( m-- )
{
scanf("%s", cmd);
if( cmd[0] == 'S' )
{
scanf("%d%d", &aa, &bb);
res = 0;
query( 0, n - 1, 1, aa, bb );
printf("%d
", res);
}
else
{
scanf("%d%d%d", &opn, &aa, &bb);
switch( cmd[0] )
{
case 'O': update(0, n-1, 1, aa, bb, opn, 0); break;
case 'A': update(0, n-1, 1, aa, bb, opn, 1); break;
case 'X': update(0, n-1, 1, aa, bb, opn, 2); break;
default : break;
}
}
}
}
return 0;
}