题目链接
题目大意
现有一个长度为 N N N 的数列 a a a,有 q q q 次操作,第一类操作为将 a i a_i ai 修改为 j j j,第二类操作为求 ⨁ i = l u ( ⨁ j = i u a j ) \bigoplus^u_{i=l}(\bigoplus^u_{j=i}{a_j}) ⨁i=lu(⨁j=iuaj)
思路分析
由异或的性质可得 a ⊕ a = 0 a\oplus a=0 a⊕a=0 且 a ⊕ 0 = a a\oplus0=a a⊕0=a,同时异或拥有交换律和结合律,所以奇数个相同的数异或等于它本身,偶数个相同的数异或等于 0 0 0。
另外,我们设 f l , r , x f_{l,r,x} fl,r,x ( l ≤ x ≤ r ) (l\le x\le r) (l≤x≤r) 表示区间 [ l , r ] [l,r] [l,r] 中包含 a x a_x ax 的子区间的个数。那么包含 a x a_x ax 的子区间必定可以表示为 a [ L , x ) a_{[L,x)} a[L,x) , a x a_x ax, a ( x , R ] a_{(x,R]} a(x,R] 三部分。第一部分有 C x − 1 − l + 1 1 + C x − 1 − l + 1 0 = x − l + 1 C^1_{x-1-l+1}+C^0_{x-1-l+1}=x-l+1 Cx−1−l+11+Cx−1−l+10=x−l+1 种取法,第三部分有 C r − ( x + 1 ) + 1 1 + C r − ( x + 1 ) + 1 0 = r − x + 1 C^1_{r-(x+1)+1}+C^0_{r-(x+1)+1}=r-x+1 Cr−(x+1)+11+Cr−(x+1)+10=r−x+1 种取法,根据乘法原理, f l , r , x = ( x − l ) × 1 × ( r − x ) = ( x − l + 1 ) ( r − x + 1 ) f_{l,r,x}=(x-l)\times1\times(r-x)=(x-l+1)(r-x+1) fl,r,x=(x−l)×1×(r−x)=(x−l+1)(r−x+1)。
因为 ( x − l + 1 ) + ( r − x + 1 ) = r − l + 2 (x-l+1)+(r-x+1)=r-l+2 (x−l+1)+(r−x+1)=r−l+2,所以当 r − l + 2 r-l+2 r−l+2 为奇数,即 l , r l,r l,r 奇偶性不同时, x − l + 1 , r − x + 1 x-l+1,r-x+1 x−l+1,r−x+1 必有一个为奇数,即 x − l , r − x x-l,r-x x−l,r−x 中必有一个为偶数,所以 f l , r , x f_{l,r,x} fl,r,x 为偶数。当 r − l + 2 r-l+2 r−l+2 为偶数,即 l , r l,r l,r 奇偶性相同时, x − l + 1 , r − x + 1 x-l+1,r-x+1 x−l+1,r−x+1 同奇偶。若两者同奇,即 l , r l,r l,r 与 x x x 奇偶性相同,则 f l , r , x f_{l,r,x} fl,r,x 为奇数,反之则为偶数。
而答案要求的等同于 ⨁ i = l u ( a i ⊕ a i ⊕ ⋯ ⊕ a i ⏟ f l , u , i 个 ) \bigoplus^u_{i=l}{(\underbrace{a_i\oplus a_i\oplus\cdots\oplus a_i}_{f_{l,u,i}\ 个})} ⨁i=lu(fl,u,i 个 ai⊕ai⊕⋯⊕ai),并且
a i ⊕ a i ⊕ ⋯ ⊕ a i ⏟ f l , u , i 个 = { a i , f l , u , i ≡ 1 ( m o d 2 ) 0 , f l , u , i ≡ 0 ( m o d 2 ) \underbrace{a_i\oplus a_i\oplus\cdots\oplus a_i}_{f_{l,u,i}\ 个}=\begin{cases} a_i&,f_{l,u,i}\equiv 1\pmod 2 \\ 0&,f_{l,u,i}\equiv 0\pmod 2 \end{cases} fl,u,i 个 ai⊕ai⊕⋯⊕ai={ai0,fl,u,i≡1(mod2),fl,u,i≡0(mod2)
所以当 l , u l,u l,u 奇偶性不同时,答案就为 0 0 0。当 l , u l,u l,u 同奇偶时,若 l , u l,u l,u 与 i i i 奇偶性相同,则 f l , u , i f_{l,u,i} fl,u,i 为奇数, a i a_i ai 对答案的贡献为 a i a_i ai;若 l , u l,u l,u 与 i i i 奇偶性不同,则 f l , u , i f_{l,u,i} fl,u,i 为偶数, a i a_i ai 对答案的贡献为 0 0 0,即当 l , u l,u l,u 同奇偶时,答案为 a l ⊕ a l + 2 ⊕ ⋯ ⊕ a u a_l\oplus a_{l+2}\oplus\cdots\oplus a_u al⊕al+2⊕⋯⊕au。
我们可以用线段树维护区间 [ l , r ] [l,r] [l,r] 中下标为奇数的元素的异或和与下标为偶数的元素的异或和。修改时只需将包含 a x a_x ax 的区间先异或原来的值,再异或修改后的值,其中两个原来 a x a_x ax 的值异或变为 0 0 0,对答案没有影响。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,q,opt,x,y;
int a[N],odd[N*4],even[N*4];// odd[] 维护奇数的异或和,even[] 维护偶数的异或和
inline void push_up(int x){
odd[x]=odd[x*2]^odd[x*2+1];
even[x]=even[x*2]^even[x*2+1];
}
void build(int l,int r,int x){
if (l==r){
if (l%2==0) even[x]=a[l];
else odd[x]=a[l];
return;
}
int mid=(l+r)/2;
build(l,mid,x*2);
build(mid+1,r,x*2+1);
push_up(x);
}
void update(int ux,int uc,int l,int r,int x){
if (l==r){
if (ux%2==0) even[x]=uc;
else odd[x]=uc;
return;
}
int mid=(l+r)/2;
if (ux<=mid) update(ux,uc,l,mid,x*2);
else update(ux,uc,mid+1,r,x*2+1);
push_up(x);
}
int query(int ul,int ur,int l,int r,int x){
if (ul<=l && ur>=r) return ul%2==0?even[x]:odd[x];
int mid=(l+r)/2,ans=0; // 若 x 与 y 同为奇数则为 [l,r] 中下标为奇数的元素的异或和
if (ul<=mid) ans^=query(ul,ur,l,mid,x*2);// 若 x 与 y 同为偶数则为 [l,r] 中下标为偶数的元素的异或和
if (ur>=mid+1) ans^=query(ul,ur,mid+1,r,x*2+1);
return ans;
}
int main(){
scanf("%d%d",&n,&q);
for (int i=1;i<=n;++i) scanf("%d",a+i);
build(1,n,1);
while (q--){
scanf("%d%d%d",&opt,&x,&y);
if (opt==1) update(x,y,1,n,1);
else printf("%d\n",(x%2==y%2?query(x,y,1,n,1):0));
}
return 0;
}