题目链接:传送门
题目大意:给n个数,m次询问,每次询问区间 l,r 内出现偶数次数的异或和
题目思路:前缀和+离线处理+树状数组
首先可以知道, l,r 内出现奇数次的数的和,就是把 l,r内所有数异或起来就是答案,那么出现偶数次的数就可以
先求出区间 l,r 内有多少不同的数,将这些数异或起来,再异或上区间内出现奇数次的数的异或和就是答案。(出现偶数次的数异或后为0,奇数次的数异或后是本身
然后离线处理询问,对询问按右端点 sort,因为树状数组保存的是数出现的最后位置。离线处理询问后便于数组的更新以及答案的更新。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> #include <stack> #include <cctype> #include <queue> #include <string> #include <vector> #include <set> #include <map> #include <climits> #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define fi first #define se second #define ping(x,y) ((x-y)*(x-y)) #define mst(x,y) memset(x,y,sizeof(x)) #define mcp(x,y) memcpy(x,y,sizeof(y)) using namespace std; #define gamma 0.5772156649015328606065120 #define MOD 1000000007 #define inf 0x3f3f3f3f #define N 1000005 #define maxn 100005 typedef pair<int,int> PII; typedef long long LL; int n,m,flag; int sum[N],tree[N],a[N]; struct Node{ int l,r; int v,id; bool operator<(const Node&a)const{ return r<a.r; } }node[N]; map<int,int>M; bool cmp(const Node&a,const Node&b){return a.id<b.id;} void add(int i,int v){for(;i<=n;i+=(i&-i))tree[i]^=v;} int getsum(int i){int res=0;for(;i;i-=(i&-i))res^=tree[i];return res;} int main(){ int i,j,group,temp; //freopen("in.txt","r",stdin); scanf("%d",&n); for(i=1;i<=n;++i){ scanf("%d",&a[i]); sum[i]=sum[i-1]^a[i]; } scanf("%d",&m); for(i=1;i<=m;++i){ scanf("%d%d",&node[i].l,&node[i].r); node[i].id=i; } sort(node+1,node+m+1); j=1; for(i=1;i<=n;++i){ int &t=M[a[i]]; if(t){ add(t,a[i]); } t=i; add(t,a[i]); while(j<=m&&node[j].r==i){ int l=node[j].l-1; int r=node[j].r; node[j].v=getsum(r)^getsum(l)^sum[r]^sum[l]; ++j; } } sort(node+1,node+m+1,cmp); for(i=1;i<=m;++i)printf("%d ",node[i].v); return 0; }