codeforces gym 100739 AQueries(区间的子区间异或和+单点修改)
题:https://codeforces.com/gym/100739/problem/A
题意:俩个操作,见标题。
分析:1、区间异或我们肯定要将序列的每个数进行二进制拆位+线段树,由题目要求只需拆出10位;
2、对于查询操作,我们可通过区间[L,R]中每个二进制位上区间异或和为1的子区间有多少个来算出答案,因为是要求子区间异或和之和,所以在每个二进制位上就表示为区间[L,R]的所有子区间的异或的值的对应二进制位上为1 的子区间的个数,所以线段树要维护的就是这个东西,由此需要其它东西来“协力”维护;
3、对于每一棵线段树的每一个节点,我们维护:𝑑表示这段区间的异或和; 𝑙0,𝑙1表示子区间从左端点开始,异或和为0/1的子区间有多少个; 𝑟0,𝑟1表示子区间从右端点开始,异或和为0/1的子区间有多少个; 𝑠0,𝑠1表示异或和为0/1的子区间一共有多少个。(这个方法和线段树维护最大子段和的方法类似)
4、合并操作:假设𝑥的左儿子𝑙𝑠,右儿子𝑟𝑠,那么:
𝑠𝑥,0 = 𝑠𝑙𝑠,0 + 𝑠𝑟𝑠,0 + 𝑟𝑙𝑠,0𝑙𝑟𝑠,0 + 𝑟𝑙𝑠,1𝑙𝑟𝑠,1
𝑠𝑥,1 = 𝑠𝑙𝑠,1 + 𝑠𝑟𝑠,1 + 𝑟𝑙𝑠,1𝑙𝑟𝑠,0 + 𝑟𝑙𝑠,0𝑙𝑟𝑠,1
𝑙𝑥,0 = 𝑙𝑙𝑠,0 + 𝑙𝑟𝑠,𝑑𝑙𝑠
𝑙𝑥,1 = 𝑙𝑙𝑠,1 + 𝑙𝑟𝑠,𝑑𝑙𝑠 xor 1
/** **/ #include<bits/stdc++.h> using namespace std; const int M=1e5+5; const int mod=4001; typedef long long ll; #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r struct node{ int d,L[2],R[2],S[2]; }tr[M<<2][11]; int a[M][11],tmp[M]; void up(int root){ int lc=root<<1,rc=root<<1|1; for(int j=0;j<10;j++){ int dl=tr[lc][j].d; int dr=tr[rc][j].d; tr[root][j].d=dl^dr; tr[root][j].L[0]=(tr[lc][j].L[0]+tr[rc][j].L[dl==0?0:1])%mod; tr[root][j].L[1]=(tr[lc][j].L[1]+tr[rc][j].L[dl==0?1:0])%mod; tr[root][j].R[0]=(tr[rc][j].R[0]+tr[lc][j].R[dr==0?0:1])%mod; tr[root][j].R[1]=(tr[rc][j].R[1]+tr[lc][j].R[dr==0?1:0])%mod; tr[root][j].S[0]=(tr[lc][j].S[0]+tr[rc][j].S[0]+(tr[lc][j].R[0]*tr[rc][j].L[0])%mod+(tr[lc][j].R[1]*tr[rc][j].L[1])%mod)%mod; tr[root][j].S[1]=(tr[lc][j].S[1]+tr[rc][j].S[1]+(tr[lc][j].R[0]*tr[rc][j].L[1])%mod+(tr[lc][j].R[1]*tr[rc][j].L[0])%mod)%mod; } } node Merge(node x,node y){ node res; res.d=res.L[0]=res.L[1]=res.R[0]=res.R[1]=res.S[0]=res.S[1]=0; int dl=x.d; int dr=y.d; res.d=dl^dr; res.L[0]=(x.L[0]+y.L[dl==0?0:1])%mod; res.L[1]=(x.L[1]+y.L[dl==0?1:0])%mod; res.R[0]=(y.R[0]+x.R[dr==0?0:1])%mod; res.R[1]=(y.R[1]+x.R[dr==0?1:0])%mod; res.S[0]=(x.S[0]+y.S[0]+(x.R[0]*y.L[0])%mod+(x.R[1]*y.L[1])%mod)%mod; res.S[1]=(x.S[1]+y.S[1]+(x.R[0]*y.L[1])%mod+(x.R[1]*y.L[0])%mod)%mod; return res; } void build(int root,int l,int r){ if(l==r){ for(int j=0;j<10;j++){ int x=a[l][j]; tr[root][j].d=x; tr[root][j].L[x]=tr[root][j].R[x]=tr[root][j].S[x]=1; } return ; } int midd=(l+r)>>1; build(lson); build(rson); up(root); } void update(int pos,int root,int l,int r){ if(l==r){ for(int j=0;j<10;j++){ int now=tmp[j]; tr[root][j].d=now; tr[root][j].L[now]=tr[root][j].R[now]=tr[root][j].S[now]=1; tr[root][j].L[now^1]=tr[root][j].R[now^1]=tr[root][j].S[now^1]=0; } return ; } int midd=(l+r)>>1; if(pos<=midd) update(pos,lson); else update(pos,rson); up(root); } node query(int L,int R,int sign,int root,int l,int r){ if(L<=l&&r<=R){ return tr[root][sign]; } int midd=(l+r)>>1; node res; res.d=res.L[0]=res.L[1]=res.R[0]=res.R[1]=res.S[0]=res.S[1]=0; if(L<=midd) res=Merge(res,query(L,R,sign,lson)); if(R>midd) res=Merge(res,query(L,R,sign,rson)); return res; } int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=0;i<=4*n;i++) for(int j=0;j<10;j++) tr[i][j].d=tr[i][j].L[0]=tr[i][j].L[1]=tr[i][j].R[0]=tr[i][j].R[1]=tr[i][j].S[0]=tr[i][j].S[1]=0; for(int x,i=1;i<=n;i++){ scanf("%d",&x); for(int j=0;j<10;j++) if(x&(1<<j)) a[i][j]=1; } build(1,1,n); while(m--){ int op,x,y; scanf("%d%d%d",&op,&x,&y); if(op==1){ memset(tmp,0,sizeof(tmp)); for(int j=0;j<10;j++) if(y&(1<<j)) tmp[j]=1; update(x,1,1,n); } else{ ll ans=0; for(int j=0;j<10;j++){ node res=query(x,y,j,1,1,n); ans=(ans+(1ll<<j)*res.S[1]%mod)%mod; } printf("%lld\n",ans); } } return 0; }