【gdkoi2016】【day1t1】【魔卡少女】【cardcaptor】【線段樹】
阿新 • • 發佈:2019-02-05
魔卡少女cardcaptor
題意:一段數,支援單點修改,查詢一段區間內子區間異或和的和。
具體做法:先做個異或字首和,[l,r] 異或和即∑sum[i]⊕sum[j](l−1<=i,j<=r)(⊕為異或) ,每個位對答案的貢獻為[l−1,r] 中零的個數乘以一的個數,至於為什麼可以自行腦補。對於修改可以把不同的位的[x,n] 的零和一的個數調換,對此可以懶標記區間修改,但是一定要記得修改完兒子後,把自己的零和一的個數重新統計一下。為此我除錯了半天~~~。可是常數巨大,貼上tle80分的程式碼。
#include<set>
#include<cmath>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const oo=2147483647;
int const maxn=100000;
int const p=100000007;
typedef struct{int x,y;}note;
inline int get(){
char ch=getchar();while((ch!='-')&&((ch<'0')||(ch>'9')))ch=getchar();
int u=1,v=0;if(ch=='-')u=-1;else v=ch-'0';ch=getchar();
while((ch>='0')&&(ch<='9'))v=v*10+ch-'0',ch=getchar();
return u*v;
}
inline char getch(){
char ch=getchar();
while((ch<'A')||(ch>'Z'))ch=getchar();
return ch;
}
int n,m,a[maxn+10],tr[maxn*6+10][10+1][2],exchange[maxn*6+10][10+1];
inline void scan(){
//srand(time(NULL));
//rand()%100;
n=get();
fo(i,1,n)
a[i]=get();
}
void add(int t,int l,int r,int i,int j,int k){
tr[t][i][j]++;
if(l==r)return;
int m=(l+r)/2;
if(k<=m)add(t*2,l,m,i,j,k);
else add(t*2+1,m+1,r,i,j,k);
}
void relax(int t,int i){
if(exchange[t][i]){
exchange[t][i]=false;
int tt=tr[t][i][0];
tr[t][i][0]=tr[t][i][1];
tr[t][i][1]=tt;
exchange[t*2][i]=!exchange[t*2][i];
exchange[t*2+1][i]=!exchange[t*2+1][i];
}
}
void updata(int t,int i){
tr[t][i][0]=tr[t*2][i][0]+tr[t*2+1][i][0];
tr[t][i][1]=tr[t*2][i][1]+tr[t*2+1][i][1];
}
ll get(int t,int l,int r,int i,int j,int l1,int r1){
relax(t,i);
if((l==l1)&&(r==r1))return tr[t][i][j];
int m=(l+r)/2,ans=0;
if(r1<=m)ans=get(t*2,l,m,i,j,l1,r1);
else if(m<l1)ans=get(t*2+1,m+1,r,i,j,l1,r1);
else ans=get(t*2,l,m,i,j,l1,m)+get(t*2+1,m+1,r,i,j,m+1,r1);
relax(t*2,i);relax(t*2+1,i);
updata(t,i);
return ans;
}
void change(int t,int l,int r,int i,int l1,int r1){
if((l==l1)&&(r==r1))
exchange[t][i]=!exchange[t][i];
relax(t,i);
if((l==l1)&&(r==r1))return;
int m=(l+r)/2;
if(r1<=m)change(t*2,l,m,i,l1,r1);
else if(m<l1)change(t*2+1,m+1,r,i,l1,r1);
else{
change(t*2,l,m,i,l1,m);
change(t*2+1,m+1,r,i,m+1,r1);
}
relax(t*2,i);relax(t*2+1,i);
updata(t,i);
}
inline void solve(){
int sum=0;
fo(i,0,n){
int tmp=sum;
fo(j,1,10){
add(1,0,n,j,tmp%2,i);
tmp/=2;
}
sum^=a[i+1];
}
m=get();
fo(i,1,m){
char ch=getch();
int x=get(),y=get();
if(ch=='Q'){
ll ans=0;
fd(j,10,1)
ans=((((1<<(j-1))*get(1,0,n,j,0,x-1,y))%p*get(1,0,n,j,1,x-1,y))%p+ans)%p;
printf("%lld\n",ans);
}
else{
int tmp=y;
fo(j,1,10){
if(a[x]%2!=tmp%2)
change(1,0,n,j,x,n);
a[x]/=2;
tmp/=2;
}
a[x]=y;
}
}
}
int main(){
scan();
solve();
return 0;
}