判断x的2进制当前第i位是1还是0,x&(1<< i)
我们要维护这段区间l[2],r[2],sum[2],zong
l[1]表示,这段区间左端点是最左边且不挨着右端点的子序段异或后,当前二进制这一位为1的个数
l[0]表示,这段区间左端点是最左边且不挨着右端点的子序段异或后,当前二进制这一位为0的个数
r[1]表示,这段区间右端点是最右边且不挨着左端点的子序段异或后,当前二进制这一位为1的个数
r[0]表示,这段区间右端点是最右边且不挨着左端点的子序段异或后,当前二进制这一位为0的个数
sum[1]表示,这段区间左和右的端点不挨着最左和最右的子序段异或后,当前二进制这一位为1的个数
sum[0]表示,这段区间左和右的端点不挨着最左和最右的子序段异或后,当前二进制这一位为0的个数
zong表示这整一段的子序段异或后的值
实际上我是900ms碾过去的,常数打的十分优美。
由于转移里面用不上sum[0],可以把它删掉优化速度。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
const int maxn=100007;
const int mo=100000007;
struct node{
int l[2],r[2],zong;
ll sum[2];
}t[10][maxn*3],ans;
using namespace std;
int i,j,k,l,n,m;
ll ans1;
char ch;
int a[maxn],mi[100];
inline int read(int n)
{
char ch=getchar();
while((ch!='-')&&((ch<'0')||(ch>'9')))ch=getchar();
int q=0,w=1;if(ch=='-')w=-1,ch=getchar();
while(ch>='0' && ch<='9'){q=q*10+ch-48;ch=getchar();}n=q*w;return n;
}
inline void merge(node &x,int lei,int xx){
node y=t[lei][xx*2],z=t[lei][xx*2+1];
x.zong=y.zong^z.zong;
x.l[0]=(y.l[0]+z.l[y.zong]+1-y.zong)%mo;
x.r[0]=(z.r[0]+y.r[z.zong]+1-z.zong)%mo;
x.l[1]=(y.l[1]+y.zong+z.l[1-y.zong])%mo;
x.r[1]=(z.r[1]+z.zong+y.r[1-z.zong])%mo;
x.sum[1]=(y.sum[1]+z.sum[1]+y.r[0]*z.l[1]+y.r[1]*z.l[0]+y.r[1]+z.l[1])%mo;
}
inline void merge1(node &x,node y,node z){
x.zong=y.zong^z.zong;
x.l[0]=(y.l[0]+z.l[y.zong]+1-y.zong)%mo;
x.r[0]=(z.r[0]+y.r[z.zong]+1-z.zong)%mo;
x.l[1]=(y.l[1]+y.zong+z.l[1-y.zong])%mo;
x.r[1]=(z.r[1]+z.zong+y.r[1-z.zong])%mo;
x.sum[1]=(y.sum[1]+z.sum[1]+y.r[0]*z.l[1]+y.r[1]*z.l[0]+y.r[1]+z.l[1])%mo;
}
inline void build(int lei,int x,int l,int r){
int mid=(l+r)/2;
if(l==r){
t[lei][x].zong=((a[l]&mi[lei])>0);
}
else{
build(lei,x*2,l,mid);
build(lei,x*2+1,mid+1,r);
merge(t[lei][x],lei,x);
}
}
inline void change(int lei,int x,int l,int r,int y){
if(l==r){
t[lei][x].zong=((a[y]&mi[lei])>0);
}
else{
int mid=(l+r)/2;
if(y<=mid) change(lei,x*2,l,mid,y);
else change(lei,x*2+1,mid+1,r,y);
merge(t[lei][x],lei,x);
}
}
void find(int lei,int x,int l,int r,int y,int z){
if(l==y&&r==z){
if (ans.zong<0) ans=t[lei][x];else
merge1(ans,ans,t[lei][x]);
}
else{
int mid=(l+r)/2;
if(z<=mid)find(lei,x*2,l,mid,y,z);
else if(y>mid)find(lei,x*2+1,mid+1,r,y,z);
else{
find(lei,x*2,l,mid,y,mid);
find(lei,x*2+1,mid+1,r,mid+1,z);
}
}
}
int main(){
scanf("%d",&n);
fo(i,1,n){
scanf("%d",&a[i]);
}
fo(j,0,9)mi[j]=(1<<j);
fo(j,0,9){
build(j,1,1,n);
}
scanf("%d",&m);
fo(i,1,m){
// scanf("%s%d%d",ch,&k,&l);
ch=getchar();
while(ch!='Q'&&ch!='M')ch=getchar();
k=read(k);
l=read(l);
ans1=0;
if(ch=='Q'){
fo(j,0,9){
ans.zong=-1;
find(j,1,1,n,k,l);
ans1=(ans1+(ans.r[1]+ans.l[1]+ans.sum[1]+ans.zong)*mi[j])%mo;
}
printf("%lld\n",ans1);
}
else{
a[k]=l;
fo(j,0,9){
change(j,1,1,n,k);
}
}
}
}