XOR(线段树)
题解:想要切这道题,你要知道以下几点:
1.异或具有结合律,即(a^b)^c=a^(b^c)
2.异或不具有分配律,即(a+b)^c≠a^c+b^c
知道了第二点,我们就不能简单的维护区间的和;知道了第一点,我们打标记以及push down就方便很多。
我们维护20棵线段树,假设第i棵线段树节点j对应区间为[l,r],该节点表示在原数列al-ar中,2^i出现的次数。然后对每个修改操作的数x用2进制表示出来,如果当前位是1,把区间中2^i的1和0的个数取反,然后注意一下push down的问题,Query和Insert的时候都要判断push down。(这个我曾经没down)
#include<iostream> #include<fstream> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> using namespace std; const int maxl=19; int n,m,jin[20]; struct tedge { int sum,t; }tree[400010][20]; long long ans; void Updata(int root,int l,int r,int wei,int x,int id) { if (l==r&&r==wei) { tree[root][id].sum++; return; } int mid=(l+r)/2; if (wei<=mid) Updata(root*2,l,mid,wei,x,id); else Updata(root*2+1,mid+1,r,wei,x,id); tree[root][id].sum=tree[root*2][id].sum+tree[root*2+1][id].sum; } void Change(int root,int l,int r,int L,int R,int id) { if (R<l||r<L) return; if (L<=l&&r<=R) { tree[root][id].sum=r-l+1-tree[root][id].sum; tree[root][id].t = 1-tree[root][id].t; return; } int mid=(l+r)/2; if (tree[root][id].t==1) { tree[root*2][id].sum=mid-l+1-tree[root*2][id].sum; tree[root*2+1][id].sum=r-(mid+1)+1-tree[root*2+1][id].sum; tree[root*2][id].t = 1-tree[root*2][id].t; tree[root*2+1][id].t = 1-tree[root*2+1][id].t; tree[root][id].t = 0; } Change(root*2,l,mid,L,R,id); Change(root*2+1,mid+1,r,L,R,id); tree[root][id].sum=tree[root*2][id].sum+tree[root*2+1][id].sum; } long long Query(int root,int l,int r,int L,int R,int id) { if (R<l||r<L) return 0; if (L<=l&&r<=R) return (long long)jin[id]*(long long)tree[root][id].sum; int mid=(l+r)/2; if (tree[root][id].t==1) { tree[root*2][id].sum=mid-l+1-tree[root*2][id].sum; tree[root*2+1][id].sum=r-(mid+1)+1-tree[root*2+1][id].sum; tree[root*2][id].t = 1-tree[root*2][id].t; tree[root*2+1][id].t = 1-tree[root*2+1][id].t; tree[root][id].t = 0; } return (long long)Query(root*2,l,mid,L,R,id)+(long long)Query(root*2+1,mid+1,r,L,R,id); } int main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%d",&n); jin[0] = 1; for (int i=1; i<=maxl; i++) jin[i] = jin[i-1]*2; for (int i=1; i<=n; i++) { int x; scanf("%d",&x); for (int j=0; j<=maxl; j++) { if (x%2==1) Updata(1,1,n,i,x%2,j); x = x/2; } } scanf("%d",&m); for (int i=1; i<=m; i++) { int id,l,r,x; ans = 0; scanf("%d%d%d",&id,&l,&r); if (id==1) { for (int j=0; j<=maxl; j++) ans+=(long long)Query(1,1,n,l,r,j); printf("%lld\n",ans); } else { scanf("%d",&x); for (int j=0; j<=maxl; j++) { if (x%2==1) Change(1,1,n,l,r,j); x = x/2; } } } return 0; }