题意:区间有三种二进制操作,区间中的值不超过16,然后查询区间和。因为每个数很小,所以区间内存在大量重复值,并且经过二进制操作后区间中相等的值会越来越多。我们只需要记录当前区间中的值是否相等即可。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
int tree[1000000*4];
int a[1000000];
void push_down(int l,int r,int k)
{
if(tree[k<<1]!=-1&&tree[k<<1|1]==tree[k<<1])
{
tree[k]=tree[k<<1];
}
}
void build(int l,int r,int k)
{
tree[k]=-1;
if(l==r)
{
tree[k]=a[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
push_down(l,r,k);
}
void update(int L,int R,int l,int r,int k,int flag,int val)
{
int mid=(L+R)>>1;
if(L>=l&&R<=r&&tree[k]!=-1)
{
if(flag==1)tree[k]^=val;
else if(flag==2)tree[k]|=val;
else if(flag==3)tree[k]&=val;
return ;
}
if(tree[k]>=0) //下传标记
{
tree[k<<1]=tree[k<<1|1]=tree[k];tree[k]=-1;
}
if(l<=mid) update(L,mid,l,r,k<<1,flag,val);
if(r>mid) update(mid+1,R,l,r,k<<1|1,flag,val);
push_down(L,R,k);//上传标记
}
int query(int L,int R,int l,int r,int k)
{
int ans=0;
int mid=(L+R)>>1;
if(L>=l&&R<=r&&tree[k]!=-1)
{
return tree[k]*(R-L+1);
}
if(tree[k]>=0) //下传标记
{
tree[k<<1]=tree[k<<1|1]=tree[k];tree[k]=-1;
}
if(l<=mid)
ans+=query(L,mid,l,r,k<<1);
if(r>mid)
ans+=query(mid+1,R,l,r,k<<1|1);
push_down(L,R,k);//上传标记
return ans;
}
int main()
{
int t;scanf("%d",&t);
while(t--)
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,n,1);
while(q--)
{
char s[5];int x,y,z;
scanf("%s",s);
if(s[0]=='S')
{
scanf("%d%d",&x,&y);x++;y++;
printf("%d\n",query(1,n,x,y,1));
}
else if(s[0]=='X')
{
scanf("%d%d%d",&z,&x,&y);x++;y++;
update(1,n,x,y,1,1,z); //orx
}
else if(s[0]=='O')
{
scanf("%d%d%d",&z,&x,&y);x++;y++;
update(1,n,x,y,1,2,z); //or
}
else
{
scanf("%d%d%d",&z,&x,&y);x++;y++; //and
update(1,n,x,y,1,3,z);
}
}
}
return 0;
}