Given N integers A={A[0],A[1],…,A[N-1]}. Here we have some operations:
Operation 1: AND opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] AND opn (here “AND” is bitwise operation).
Operation 2: OR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] OR opn (here “OR” is bitwise operation).
Operation 3: XOR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] XOR opn (here “XOR” is bitwise operation).
Operation 4: SUM L R
We want to know the result of A[L]+A[L+1]+...+A[R] .
Now can you solve this easy problem?
Input
The first line of the input contains an integer T, indicating the number of test cases. (T≤100)
Then T cases, for any case, the first line has two integers n and m (1≤n≤1,000,000, 1≤m≤100,000), indicating the number of elements in A and the number of operations.
Then one line follows n integers A[0],A[1],...,A[n−1](0≤A[i]<16,0≤i<n) .
Then m lines, each line must be one of the 4 operations above. (0≤opn≤15)
Output
For each test case and for each “SUM” operation, please output the result with a single line.
Sample Input
1
4 4
1 2 4 7
SUM 0 2
XOR 5 0 0
OR 6 0 3
SUM 0 2
Sample Output
7
18
思路:因为看到每个数的大小不超过15,想了是可以能用位运算什么的,但是真没想到用是直接拆出来建4棵线段树,写完以后想想,也的确如此,不然怎么加和呢..
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxx 1000005
using namespace std;
int n,m;
int a[maxx];
int tr[4][maxx<<2];
int lazy[4][maxx<<2];
int lazy_xor[4][maxx<<2];
char com[5];
void pushDown(int id,int rt,int l,int r)
{
int mid=(l+r)>>1;
if(lazy[id][rt]!=-1)//and 和or 运算比xor级别要高,不然先后顺序很难控制,
{
lazy_xor[id][rt<<1]=lazy_xor[id][rt<<1|1]=0;
lazy[id][rt<<1]=lazy[id][rt<<1|1]=lazy[id][rt];
tr[id][rt<<1]=lazy[id][rt]*(mid-l+1);
tr[id][rt<<1|1]=lazy[id][rt]*(r-mid);
lazy[id][rt]=-1;
}
int &q=lazy_xor[id][rt];
if(q==1)
{
lazy_xor[id][rt<<1]^=1;
lazy_xor[id][rt<<1|1]^=1;
tr[id][rt<<1]=mid-l+1-tr[id][rt<<1];
tr[id][rt<<1|1]=r-mid-tr[id][rt<<1|1];
q=0;
}
}
void pushUp(int id,int rt)
{
tr[id][rt]=tr[id][rt<<1]+tr[id][rt<<1|1];
}
void build(int id,int rt,int l,int r)
{
lazy[id][rt]=-1;
lazy_xor[id][rt]=0;
if(l==r)
{
if(a[r]&(1<<id))
tr[id][rt]=1;
else
tr[id][rt]=0;
return;
}
int mid=(r+l)>>1;
build(id,rt<<1,l,mid);
build(id,rt<<1|1,mid+1,r);
pushUp(id,rt);
}
void update(int id,int rt,int l,int r,int L,int R,int x)
{
if(L<=l&&r<=R)
{
if(x==2)//同样的看是否有and 或 or的操作
{
if(lazy[id][rt]!=-1)lazy[id][rt]^=1;
else lazy_xor[id][rt]^=1;
tr[id][rt]=(r-l+1)-tr[id][rt];
}
else
{
lazy[id][rt]=x;
lazy_xor[id][rt]=0;
tr[id][rt]=x*(r-l+1);
}
return;
}
pushDown(id,rt,l,r);
int mid=(l+r)>>1;
if(L<=mid)
update(id,rt<<1,l,mid,L,R,x);
if(R>mid)
update(id,rt<<1|1,mid+1,r,L,R,x);
pushUp(id,rt);
}
int query(int id,int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
return tr[id][rt];
pushDown(id,rt,l,r);
int mid=(l+r)>>1;
int res=0;
if(L<=mid)res+=query(id,rt<<1,l,mid,L,R);
if(R>mid)res+=query(id,rt<<1|1,mid+1,r,L,R);
return res;
}
int main()
{
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<4;i++)
build(i,1,0,n-1);
int o,b,c;
while(m--)
{
scanf("%s",com);
if(com[0]=='S')
{
scanf("%d%d",&b,&c);
int ans=0;
for(int i=0;i<4;i++)
ans+=query(i,1,0,n-1,b,c)*(1<<i);
printf("%d\n",ans);
}
else
{
scanf("%d%d%d",&o,&b,&c);
if(com[0]=='X'){
for(int i=0;i<4;i++)
if(o&(1<<i))
update(i,1,0,n-1,b,c,2);
}
else
if(com[0]=='O'){
for(int i=0;i<4;i++)
if(o&(1<<i))
update(i,1,0,n-1,b,c,1);
}
else
{
for(int i=0;i<4;i++)
if(!(o&(1<<i)))
update(i,1,0,n-1,b,c,0);
}
}
}
}
return 0;
}