题意:求区间上出现偶数次的数 的异或和。
分析: 如果求出现奇数次的数 的异或和,则只需预处理前缀异或和,然后马上就能求出来了。一个数异或偶数次为0。
所以这题把问题简单化,把偶数次变奇数次,奇数次变偶数次。(主要思想)
1. 预处理前缀异或和(偶数次被异或没了)
2.pre数组记录当前数上一次出现的位置,没出现过则为0
3.先把查询记录下来,按右端点排序,方便后面查询,具体看代码。
4.将元素一个个按位置加进树状数组,如果这个数前面出现过,则在上一次出现的位置异或下这个数,然后再在当前位置加入这个数(相当于把偶数次变奇数次)。
简单说就是求区间所有数的异或和(去掉重复的)。
5.这个区间的前缀异或和 异或 区间所有数的异或和(去掉重复的)得到结果。
这一步是去除区间出现奇数次的数。
第一次在cf用cin cout会T,改用scanf printf 过了 题目给了3.5s 大概用了1.6s
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const long long INF = 1e18;
const int N= 1e6+10;
const int maxn = 1e6+10;
const int maxm = 2000000001;
const int MOD = 1e6;
int A[maxn],n;
void ADD(int x, int c)
{
for (int i=x; i<=n; i+=i&(-i)) A[i] ^= c;
}
int SUM(int x)
{
int s = 0;
for (int i=x; i>0; i-=i&(-i)) s ^= A[i];
return s;
}
struct Node{
int l,r,pos;
}qu[maxn];
map<int,int> mp;
int ans[maxn];
int sum[maxn],a[maxn],pre[maxn];
bool cmp(Node xx,Node yy)
{
return xx.r<yy.r;
}
int main(){
#ifdef LOCAL
freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
//freopen("output.txt","w",stdout);
#endif
//ios_base::sync_with_stdio(0);
scanf("%d",&n);
sum[0] = 0;
//mp.clear();memset(ans,0,sizeof(ans));
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
sum[i] = sum[i-1]^a[i];
pre[i] = mp[a[i]];
mp[a[i]] = i;
}
int q;
scanf("%d",&q);
for(int i = 1; i <= q; i++)
{
scanf("%d%d",&qu[i].l,&qu[i].r);
qu[i].pos = i;
}
sort(qu+1,qu+q+1,cmp);
int j = 1;
for(int i = 1; i <= q; i++)
{
for( ;j <= qu[i].r; j++)
{
if (pre[j]) ADD(pre[j],a[j]);
ADD(j,a[j]);
}
ans[qu[i].pos] = sum[qu[i].r]^sum[qu[i].l-1]^SUM(qu[i].r)^SUM(qu[i].l-1);
}
for(int i = 1; i <= q; i++) printf("%d\n",ans[i]);
return 0;
}