由於本題求和的優先級高於異或,所以最后其實是一坨求和之后的數再異或起來,於是我們就可以拆位做啦。
然后原問題簡化成了:對於每一位,有多少區間和在這一位上是1。
假如現在處理到 2^i 這位,然后我們枚舉區間右端點j,想要可以快速找到所有左端點l,滿足 sum[j] - sum[l-1] 在 2^i 這位為1(為0不用管,對異或無影響)。
可以發現 sum[j] > sum[l-1] 必然成立,不妨設 lef[x] 為每個位置的數 僅保留后 i 位 得到的數 (即2^0,2^1,.....,2^(i-1)這些位),那么可以得到:
lef[x] >= lef[l-1] 時,當且僅當 sum[j]^sum[l-1] 在 2^i 這位為1時,j與l-1是一個我們需要的區間;
類似的,lef[x]<lef[l-1]時,當且僅當 sum[j]^sum[l-1] 在 2^i 這位為0時,j與l-1是一個我們需要的區間;
然后這就是個樹狀數組題了23333(后面還有個細節,因為樹狀數組里面最小的下標是1,所以要對下標做一些修改)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5,M=1e6+5;
inline int read(){
int x=0; char ch=getchar();
for(;!isdigit(ch);ch=getchar());
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
int n,a[N],f[2][M],ans,i,now,oe;
inline void update(int T,int x){
for(;x<=i;x+=x&-x) f[T][x]^=1;
}
inline int query(int T,int x){
int an=0;
for(;x;x-=x&-x) an^=f[T][x];
return an;
}
int main(){
n=read();
for(i=1;i<=n;i++) a[i]=read()+a[i-1];
for(i=1,now=0,oe;i<=a[n];now|=i,i<<=1){
memset(f,0,sizeof(f)),oe=0;
update(0,1);
for(int j=1,u,p;j<=n;j++){
u=(a[j]&i)?1:0,p=(a[j]&now)+1;
oe^=query(u^1,p)^query(u,i)^query(u,p);
update(u,p);
}
ans+=i*oe;
}
printf("%d\n",ans);
return 0;
}
