http://codeforces.com/problemset/problem/703/D
题意是给一个序列,多次询问一段区间内出现偶数次数的数字的异或和。n,m<100w,时限3.5s。这样好像是卡 莫队n*sqrt(n)做法。可以nlogn做。
input
7
1 2 1 3 3 2 3
5
4 7
4 5
1 3
1 7
1 5
output
0
3
1
3
2
出现偶数次的异或和可以用前缀和 异或 区间去重异或和 来求。这东西可以用树状数组维护(Orz)。考虑1~r的询问,先把每个数第一次出现的位置加入树状数组,查询时找r前面出现的数就可以。所以说可以把询问按左端点大小排序,第次i询问后,把i~i+1左端点之间的每一个点删去,在这个数下一个出现位置添加修改;
#include<bits/stdc++.h>
#define maxn 1000005
using namespace std;
void read(int &a)
{
a=0;char c=getchar();
while(c<'0'||c>'9')
c=getchar();
while(c>='0'&&c<='9')
{
a*=10;a+=c-'0';
c=getchar();
}
}
struct QUE{
int l,r,id,ans;
}q[maxn];
bool cmp(QUE a,QUE b)
{return a.l<b.l;}
bool cmp2(QUE a,QUE b)
{return a.id<b.id;}
int a[maxn],sum[maxn];
int nxt[maxn];
map<int,int> mp;
int c[maxn];
int n;
void change(int x,int d)
{
while(x<=n)
{
c[x]^=d;
x+=x&(-x);
}
}
int ask(int x)
{
int ans=0;
while(x>0)
{
ans^=c[x];
x-=x&(-x);
}
return ans;
}
int ask(int l,int r)
{
int ans=sum[r]^sum[l-1];
ans^=ask(r);
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
read(a[i]);
sum[i]=sum[i-1]^a[i];
nxt[i]=n+1;
}
for(int i=n;i>=1;i--)
nxt[i]=mp[a[i]],mp[a[i]]=i;
int m;read(m);
for(int i=1;i<=m;i++)
read(q[i].l),read(q[i].r),q[i].id=i;
for(int i=1;i<=n;i++)
if(mp[a[i]]==i) change(i,a[i]);
sort(q+1,q+m+1,cmp);
int now=1;
for(int i=1;i<=m;i++)
{
while(now<q[i].l)
{
change(now,a[now]);
if(nxt[now])
change(nxt[now],a[now]);
now++;
}
q[i].ans=ask(q[i].l,q[i].r);
}
sort(q+1,q+m+1,cmp2);
for(int i=1;i<=m;i++)
printf("%d\n",q[i].ans);
}