題意:明顯的線段樹,對一個區間進行操作,操作包括與,或,異或,求和四種,也就是三種操作(均爲位運算),一個詢問。不過每個數字都很小,[0,16],這很奇怪,而且位運算每位之間是獨立的,所以可以用四個線段樹分別維護每一位,求和的時候求四次,加起來就可以。
對於與操作:如果某一位爲1,操作之後不產生變化,所以只考慮0的情況,0的時候全變爲0,相當於覆蓋
對於或操作:如果某一位爲0,不產生變化,只考慮1,相當於覆蓋爲1
對於異或:0,不產生變化,1相當於每一位均取反
所以整理之後有兩種操作,一種是區間覆蓋,一種是區間取反,這兩種操作明顯不是一類的,所以需要用兩個延遲標記,不過兩個延遲標記又產生了順序的問題,參考題解後發現是這樣處理的:當對一個區間進行操作的時候,需要先看看有沒有其他的操作(兩種都需要考慮),然後採取不同的操作。也就是一個區間的延遲標記不能同時有標記(如果與順序無關的話就不用這麼麻煩了),這樣就木有問題了=。=
代碼:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 1000000+5;
bool XOR[4][maxn<<2];
int OR[4][maxn<<2];
int sum[4][maxn<<2];
int nn[maxn];
void pushup(int id,int rt){
sum[id][rt] = (sum[id][rt<<1] + sum[id][rt<<1|1]);
}
void build(int id,int l,int r,int rt){
XOR[id][rt] = 0;
OR[id][rt] = -1;
if(l == r){
bool ii = (nn[l]&(1<<id))!=0?1:0;
sum[id][rt] = ii;
//cout<<id<<' '<<ii<<endl;
return ;
}
int m = (l + r) >> 1;
build(id,lson);
build(id,rson);
pushup(id,rt);
}
void pushdown(int id,int rt,int m){
if(OR[id][rt] != -1){
OR[id][rt<<1] = OR[id][rt<<1|1] = OR[id][rt];
XOR[id][rt<<1] = XOR[id][rt<<1|1] = 0;
sum[id][rt<<1] = OR[id][rt<<1] * (m - (m>>1));
sum[id][rt<<1|1] = OR[id][rt<<1|1] * (m>>1);
OR[id][rt] = -1;
}
if(XOR[id][rt] == 1){
if(OR[id][rt<<1] != -1)OR[id][rt<<1] ^= 1;
else XOR[id][rt<<1] ^= 1;
if(OR[id][rt<<1|1] != -1)OR[id][rt<<1|1] ^= 1;
else XOR[id][rt<<1|1] ^= 1;
sum[id][rt<<1] = (m - (m>>1)) - sum[id][rt<<1];
sum[id][rt<<1|1] = (m>>1) - sum[id][rt<<1|1];
XOR[id][rt] = 0;
}
}
void update_OR(int id,int L,int R,int c,int l,int r,int rt){
if(L <= l&&r <= R){
XOR[id][rt] = 0;
OR[id][rt] = c;
sum[id][rt] = c*(r - l + 1);
return ;
}
pushdown(id,rt,r-l+1);
int m = (l + r) >>1;
if(L <= m)update_OR(id,L,R,c,lson);
if(m < R)update_OR(id,L,R,c,rson);
pushup(id,rt);
}
void update_XOR(int id,int L,int R,int l,int r,int rt){
if(L <= l&&r <= R){
if(OR[id][rt] != -1){
OR[id][rt] ^= 1;
}
else {
XOR[id][rt] ^= 1;
}
sum[id][rt] = (r - l + 1) - sum[id][rt];
return ;
}
pushdown(id,rt,r-l+1);
int m = (l + r)>>1;
if(L <= m)update_XOR(id,L,R,lson);
if(m < R)update_XOR(id,L,R,rson);
pushup(id,rt);
}
int query(int id,int L,int R,int l,int r,int rt){
if (L <= l && r <= R) {
return sum[id][rt];
}
pushdown(id,rt , r - l + 1);
int m = (l + r) >> 1;
int ret = 0;
if (L <= m) ret += query(id,L , R , lson);
if (m < R) ret += query(id,L , R , rson);
return ret;
}
int main(){
//freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T --){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++)scanf("%d",&nn[i]);
for(int i = 0;i < 4;i ++){
build(i,1,n,1);//cout<<i<<"aaaaaaaaaa";
}
char s[20];
int l,r,op;
while(m --){
scanf("%s",s);
if(s[0] == 'S'){
scanf("%d%d",&l,&r);l++;r++;
int ans = 0;
for(int i = 3;i >= 0;i --){
ans += (1<<i)*query(i,l,r,1,n,1);
}
printf("%d\n",ans);
}
else if(s[0] == 'X'){
scanf("%d%d%d",&op,&l,&r);l++;r++;
for(int i = 0;i < 4;i ++){
if(op&(1<<i))
update_XOR(i,l,r,1,n,1);
}
}
else if(s[0] == 'A'){
scanf("%d%d%d",&op,&l,&r);l++;r++;
for(int i = 0;i < 4;i ++){
if(!(op&(1<<i)))
update_OR(i,l,r,0,1,n,1);
}
}
else if(s[0] == 'O'){
scanf("%d%d%d",&op,&l,&r);l++;r++;
for(int i = 0;i < 4;i ++){
if(op&(1<<i))
update_OR(i,l,r,1,1,n,1);
}
}
}
}
return 0;
}