由于各项数据范围都是0-15,所有把一个数拆成四位二进制数来维护,对应三种操作分别不同分别跑循环操作一下就可以。
更新lazy的时候会比较麻烦。
要注意如果你默认lazy操作为and, or, xor对应的lazy值分别为0,1,1(因为只有这些值会对结果产生影响),对xor对应的值直接异或的话,需要把异或后为0的lazy标记直接抹去。
大概就是这样了,然后不要整个数组都memset会省去一半的时间。
代码:
#include <iostream>
#include <stdio.h>
#include <cstring>
#define lson o<<1
#define rson o<<1|1
#define MID int mid=(l+r)>>1;
#define LL long long
using namespace std;
const int maxn=1e6+5;
int val[maxn<<2][4];
int lazy[maxn<<2][4];
int lazyop[maxn<<2][4];
int a[maxn];
int num[5];
void cal(int x)
{
int i=0;
for(int j=0; j<4; j++)
{
num[i++]=x%2;
x/=2;
}
return;
}
int sum(int o)
{
int res=0, x=1;
for(int i=0; i<4; i++)
{
res+=x*val[o][i];
x*=2;
}
return res;
}
void build(int o, int l, int r)
{
if(l==r)
{
cal(a[l]);
for(int i=0; i<4; i++)val[o][i]+=num[i];
return;
}
MID;
build(lson, l, mid);
build(rson, mid+1, r);
for(int i=0; i<4; i++)val[o][i]=val[lson][i]+val[rson][i];
return;
}
void push_down(int o, int l, int r)
{
MID;
for(int i=0; i<4; i++)
{
/*
if(r==10)
{
printf("%d %d %d\n", l, r, lazyop[o][i]);
}
*/
switch (lazyop[o][i])
{
case 1:
{
val[lson][i]=0;
val[rson][i]=0;
lazyop[lson][i]=1, lazy[lson][i]=0;
lazyop[rson][i]=1, lazy[rson][i]=0;
break;
}
case 2:
{
val[lson][i]=mid-l+1;
val[rson][i]=r-(mid+1)+1;
lazyop[lson][i]=2, lazy[lson][i]=1;
lazyop[rson][i]=2, lazy[rson][i]=1;
break;
}
case 3:
{
val[lson][i]=(mid-l+1)-val[lson][i];
val[rson][i]=(r-(mid+1)+1)-val[rson][i];
lazy[lson][i]^=1;
if(lazyop[lson][i]==1)lazyop[lson][i]=2;
else if(lazyop[lson][i]==2)lazyop[lson][i]=1;
else if(lazyop[lson][i]==0)lazyop[lson][i]=3, lazy[lson][i]=1;
if(lazyop[lson][i]==3 && lazy[lson][i]==0)lazyop[lson][i]=0;
lazy[rson][i]^=1;
if(lazyop[rson][i]==1)lazyop[rson][i]=2;
else if(lazyop[rson][i]==2)lazyop[rson][i]=1;
else if(lazyop[rson][i]==0)lazyop[rson][i]=3, lazy[rson][i]=1;
if(lazyop[rson][i]==3 && lazy[rson][i]==0)lazyop[rson][i]=0;
break;
}
}
lazyop[o][i]=0;
lazy[o][i]=0;
}
// printf("\n");
return;
}
void update(int o, int l, int r, int ll, int rr, int op)
{
if(ll<=l && r<=rr)
{
if(op==1){for(int i=0; i<4; i++)if(num[i]==0){val[o][i]=0;lazy[o][i]=0;lazyop[o][i]=1; } }
if(op==2){for(int i=0; i<4; i++)if(num[i]==1){val[o][i]=r-l+1;lazy[o][i]=1;lazyop[o][i]=2; } }
if(op==3){
for(int i=0; i<4; i++)
{
if(num[i]==1)
{
val[o][i]=r-l+1-val[o][i];
if(lazyop[o][i]==1)lazyop[o][i]=2, lazy[o][i]=1;
else if(lazyop[o][i]==2)lazyop[o][i]=1, lazy[o][i]=0;
else if(lazyop[o][i]==3)lazy[o][i]^=num[i], lazyop[o][i]=lazy[o][i]?3:0;
else lazy[o][i]=1, lazyop[o][i]=3;
}
}
}
return;
}
push_down(o, l, r);
MID;
if(ll<=mid)update(lson, l, mid, ll, rr, op);
if(rr>mid)update(rson, mid+1, r, ll, rr, op);
for(int i=0; i<4; i++)val[o][i]=val[lson][i]+val[rson][i];
return;
}
int query(int o, int l, int r, int ll, int rr)
{
if(ll<=l && r<=rr)
{
return sum(o);
}
push_down(o, l, r);
MID;
int res=0;
if(ll<=mid)res+=query(lson, l, mid, ll, rr);
if(rr>mid)res+=query(rson, mid+1, r, ll, rr);
for(int i=0; i<4; i++)val[o][i]=val[lson][i]+val[rson][i];
return res;
}
int main()
{
// freopen("C:\\Users\\johsnow\\Desktop\\data.in", "r", stdin);
// freopen("C:\\Users\\johsnow\\Desktop\\ans.out", "w", stdout);
int t, n, m, x, i, j, l, r;
char str[10];
cin>>t;
while(t--)
{
scanf("%d%d", &n, &m);
for(i=0; i<=4*n; i++)
{
memset(lazy[i], 0, sizeof lazy[i]);
memset(lazyop[i], 0, sizeof lazyop[i]);
memset(val[i], 0, sizeof val[i]);
}
for(i=1; i<=n; i++)
{
scanf("%d", &a[i]);
}
build(1, 1, n);
while(m--)
{
scanf("%s", str);
if(str[0]=='S')
{
scanf("%d%d", &l, &r);
l++, r++;
printf("%d\n", query(1, 1, n, l, r));
}
else if(str[0]=='O')
{
scanf("%d%d%d", &x, &l, &r);
l++, r++;
cal(x);
update(1, 1, n, l, r, 2);
}
else if(str[0]=='X')
{
scanf("%d%d%d", &x, &l, &r);
l++, r++;
cal(x);
update(1, 1, n, l, r, 3);
}
else if(str[0]=='A')
{
scanf("%d%d%d", &x, &l, &r);
l++, r++;
cal(x);
update(1, 1, n, l, r, 1);
}
}
}
}