CodeForces 703D Mishka and Interesting sum
异或运算性质,离线操作,区间求异或和。
直接求区间出现偶数次数的异或和并不好算,需要计算反面。
首先,很容易求解区间异或和,记为$P$。
例如下面这个序列,$P = A[1]xorA[2]xorA[3]......xorA[15]$
$1$,$1$,$1$,$2$,$2$,$3$,$3$,$3$,$4$,$4$,$5$,$5$,$6$,$7$,$7$。
出现偶数次数的异或和记为$Q$,那么$Q = 2xor4xor5xor7$。
我们记$F=PxorQ$,如果知道$F$,那么就能计算出$Q$。所以接下来我们来看一下$F$是什么东西。
$F = 1xor1xor1xor2xor3xor3xor3xor4xor5xor6xor7 = 1xor2xor3xor4xor5xor6xor7$。
也就是说,$F$为区间去重之后的那些数的异或和。
那么,接下来问题变成了如何求解区间去重之后的数字的异或和。这个问题和$HDU3333$一模一样,只不过从$+$变成了$xor$。
$HDU3333$:$http://www.cnblogs.com/zufezzt/p/5805327.html$
求得了$F$之后,我们只需将$PxorF$,即可得到$Q$。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0),eps=1e-8; void File() { freopen("D:\\in.txt","r",stdin); freopen("D:\\out.txt","w",stdout); } const int maxn=1000010; int T,n; int a[maxn],c[maxn],sum[maxn],Ans[maxn]; struct X { int id,L,R;LL ans; }q[maxn]; bool cmp(X a,X b) { return a.R<b.R; } bool cmp1(X a,X b) { return a.id<b.id; } int lowbit(int x) { return x&(-x); } void update(int p,LL v) { while(p<=n) c[p]=c[p]^v,p=p+lowbit(p); } int XOR(int p) { int res=0; while(p>0) res=res^c[p],p=p-lowbit(p); return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]^a[i]; map<int,int>m; int Q; scanf("%d",&Q); for(int i=1;i<=Q;i++) scanf("%d%d",&q[i].L,&q[i].R),q[i].id=i; sort(q+1,q+1+Q,cmp); int p=1; for(int i=1;i<=n;i++) { int h=m[a[i]]; if(h!=0) update(h,a[i]); update(i,a[i]); m[a[i]]=i; while(p<=Q&&q[p].R==i) q[p].ans=XOR(q[p].R)^XOR(q[p].L-1), p++; } for(int i=1;i<=Q;i++) Ans[q[i].id]=sum[q[i].R]^sum[q[i].L-1]^q[i].ans; for(int i=1;i<=Q;i++) printf("%d\n",Ans[i]); return 0; }