题目大意
给定长度为n的序列A,定义关于A的函数
$f(l,r) = a_l⊕a_{l+1}⊕⋯⊕a_r$,
$F(l,r)=f(l,l)⊕f(l,l+1)⊕..⊕f(l,r)⊕f(l+1,l+1)⊕..⊕f(l+1,r)⊕..⊕f(r,r)$
定义两个操作:
- $0\space x\space y$代表将$A[x]$的值更改为$y$
- $1\space l\space r$代表需要计算$F(l,r)$的值
输出每一次第二个操作得到的结果
解题思路
对于$Xor$运算,肯定是判断每个元素次数的奇偶性,通过分析可以很快知道,对于函数$F(l,r)$:$若(r-l+1)为奇数则F(l,r)=A[l]⊕A[l+2]⊕A[l+4]⊕…⊕A[r]$
$若(r-l+1)为偶数则F(l,r)=0$
题目操作涉及到单点修改与区间求值,所以可以用树状数组处理,在每个节点上存储区间异或和,但是由A数组直接建立树状数组,对于求F函数的值时,区间不是连续的,所以可将A数组的奇数项与偶数项分别用两个树状数组来存储,使其连续。
对于单点修改的操作,相当于是先异或求改前的值去除影响,再将得到的结果与新值异或,所以我们可直接对相关节点直接异或$(A[x]⊕y)$
AC代码
样例输入
1
3 3
1 2 3
1 1 3
0 1 2
1 1 1
样例输出
Case #1:
2
2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
| #include<bits/stdc++.h> using namespace std;
long long a[1000002],c1[1000002],c2[1000002],tt,n,m; long long lowbit(long long x) {return x&(-x);} void add1(long long i,long long x) { while(i<=n) { c1[i]^=x; i+=lowbit(i); } } long long sum1(long long x) { long long ans=0; while(x>0) { ans^=c1[x]; x-=lowbit(x); } return ans; } void add2(long long i,long long x) { while(i<=n) { c2[i]^=x; i+=lowbit(i); } } long long sum2(long long x) { long long ans=0; while(x>0) { ans^=c2[x]; x-=lowbit(x); } return ans; }
int main(){ scanf("%lld",&tt); for(long long ii=1;ii<=tt;++ii){ scanf("%lld%lld",&n,&m); for(long long i=1;i<=n;++i){ c1[i]=0; c2[i]=0; } for(long long i=1;i<=n;++i){ scanf("%lld",&a[i]); if(i%2){ add1((i+1)/2,a[i]); } else{ add2((i)/2,a[i]); } } long long x,y,z; printf("Case #%lld:\n",ii); for(long long i=1;i<=m;++i){ scanf("%lld%lld%lld",&x,&y,&z); if(x==1){ if((z-y+1)%2){ if(y%2){ printf("%lld\n",sum1((z+1)/2)^sum1((y+1)/2-1)); } else{ printf("%lld\n",sum2(z/2)^sum2(y/2-1)); } } else{ printf("0\n"); } } else{ if(y%2){ add1((y+1)/2,a[y]^z); } else{ add2(y/2,a[y]^z); } a[y]=z; } } } return 0; }
|
Last updated: