题意:给你N个数,有四种操作。(1)"AND opn L R",表示对区间[L,R]内的数全部与opn进行且(&)操作。(2)"OR opn L R",表示对区间[L,R]内的数全部与opn进行或(|)操作。(3)"XOR opn L R",表示对区间[L,R]内的数全部与opn进行异或(^)操作。(4)"SUM opn L R",求出区间[L,R]的数的和。
注意到给出的N个数的和opn的范围只有0-15(用二进制看,就是只有4位),把每个数的每一位单独拉出来,建一次线段树,得到每个询问内每一位有多少个1,就得到最后的答案。
说白了,就是全部赋值为1或者0,并且把区间里面0和1的数目对换,即翻转。我们定义前者为操作1(赋值为0或1可以合并起来处理不是?),后者为操作2。那么如果先进行操作2,再进行操作1,操作2是失效的,因为无论先怎么交换,再把它们赋值成0或1,结果都是一样的。但是,如果先进行操作1,再无进行操作2,结果是不一样的,因为先赋值,再翻转的话,就会把原来全部赋值为1的变成全部为0,反之同理。所以我们必须先传递操作1,再传递操作2,同时在传递操作1时,如果有操作2的标记,那么我们要把操作2的标记去除(因为它失效了)。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define MID(a,b) (a+((b-a)>>1)) const int N=1e6+5; int a[N],n,m; struct Segtree { int cnt0[N*4],cnt1[N*4],flag[N*4],flag_x[N*4]; void fun(int ind,int iflag,int iflag_x,int lft,int rht) { if(iflag!=-1) { flag[ind]=iflag; if(iflag==0) cnt0[ind]=rht-lft+1,cnt1[ind]=0; else if(iflag==1) cnt1[ind]=rht-lft+1,cnt0[ind]=0; flag_x[ind]=0; } if(iflag_x) { flag_x[ind]^=1; swap(cnt0[ind],cnt1[ind]); } } void PushDown(int ind,int lft,int rht) { if(flag[ind]!=-1||flag_x[ind]==1) { int mid=MID(lft,rht); fun(LL(ind),flag[ind],flag_x[ind],lft,mid); fun(RR(ind),flag[ind],flag_x[ind],mid+1,rht); flag[ind]=-1; flag_x[ind]=0; } } void PushUp(int ind) { cnt0[ind]=cnt0[LL(ind)]+cnt0[RR(ind)]; cnt1[ind]=cnt1[LL(ind)]+cnt1[RR(ind)]; } void build(int lft,int rht,int ind,int bit) { cnt0[ind]=0; cnt1[ind]=0; flag[ind]=-1; flag_x[ind]=0; if(lft==rht) { if((a[lft]&(1<<bit))==0) cnt0[ind]=1; else cnt1[ind]=1; } else { int mid=MID(lft,rht); build(lft,mid,LL(ind),bit); build(mid+1,rht,RR(ind),bit); PushUp(ind); } } void updata(int st,int ed,int iflag,int iflag_x,int lft,int rht,int ind) { if(st<=lft&&rht<=ed) fun(ind,iflag,iflag_x,lft,rht); else { PushDown(ind,lft,rht); int mid=MID(lft,rht); if(st<=mid) updata(st,ed,iflag,iflag_x,lft,mid,LL(ind)); if(ed> mid) updata(st,ed,iflag,iflag_x,mid+1,rht,RR(ind)); PushUp(ind); } } int query(int st,int ed,int lft,int rht,int ind) { if(st<=lft&&rht<=ed) return cnt1[ind]; else { PushDown(ind,lft,rht); int mid=MID(lft,rht),num=0; if(st<=mid) num+=query(st,ed,lft,mid,LL(ind)); if(ed> mid) num+=query(st,ed,mid+1,rht,RR(ind)); PushUp(ind); return num; } } }seg; struct OP { char cmd[10]; int opn,L,R,cnt[5]; void get() { memset(cnt,0,sizeof(cnt)); scanf("%s",cmd); if(cmd[0]=='S') scanf("%d%d",&L,&R); else scanf("%d%d%d",&opn,&L,&R); L=max(0,L); R=min(n-1,R); } void print() { for(int i=0;i<4;i++) printf("%d ",cnt[i]);puts(""); } }op[100005]; void solve(int bit) { seg.build(0,n-1,1,bit); for(int i=0;i<m;i++) { if(op[i].cmd[0]=='A') { if(op[i].opn&(1<<bit)) continue; else seg.updata(op[i].L,op[i].R,0,0,0,n-1,1); } else if(op[i].cmd[0]=='O') { if(op[i].opn&(1<<bit)) seg.updata(op[i].L,op[i].R,1,0,0,n-1,1); else continue; } else if(op[i].cmd[0]=='X') { if(op[i].opn&(1<<bit)) seg.updata(op[i].L,op[i].R,-1,1,0,n-1,1); else continue; } else { op[i].cnt[bit]=seg.query(op[i].L,op[i].R,0,n-1,1); } } } int main() { //freopen("D.in","r",stdin); int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<m;i++) op[i].get(); for(int i=0;i<4;i++) solve(i); for(int i=0;i<m;i++) if(op[i].cmd[0]=='S') { int ans=op[i].cnt[0]+op[i].cnt[1]*2+op[i].cnt[2]*2*2+op[i].cnt[3]*2*2*2; // op[i].print(); printf("%d\n",ans); } } return 0; }