- 首先利用异或的性质,把要维护的信息等价转化成L到R的所有数XOR值再异或上L到R所有出现了的数的异或值,问题转化为如何求一个区间中所有出现过的数的异或值
- 和clay17与segMilkTrea一题有异曲同工之妙。考虑离线维护,首先朴素地求出[1,1],[1,2],[1,3],...,[1,n]区间的答案,然后发现只要快速地修改区间[1,nx[1]-1]就可以得到[2,2],[2,3],...,[2,n]区间的答案,使用支持区间修改、单点查询的线段树维护即可
#include <bits/stdc++.h>
using namespace std;
int a[1000005],s[1000005],nx[1000005],ans[1000005];
bool v[1000005];
unordered_map<int,int>h;
struct q1
{
int l,r,id;
}q[1000005];
bool cmp(q1 a,q1 b)
{
return a.l<b.l;
}
struct t1
{
int l,r;
int v,bj;
}t[4000005];
void build(int p,int l,int r)
{
t[p].l=l;
t[p].r=r;
t[p].v=t[p].bj=0;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].v=t[p*2].v^t[p*2+1].v;
}
void spread(int p)
{
t[p*2].bj^=t[p].bj;
t[p*2+1].bj^=t[p].bj;
t[p*2].v^=t[p].bj;
t[p*2+1].v^=t[p].bj;
t[p].bj=0;
}
void change(int p,int l,int r,int v)
{
if(l<=t[p].l&&r>=t[p].r)
{
t[p].v^=v;
t[p].bj^=v;
return;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)
{
change(p*2,l,r,v);
}
if(r>mid)
{
change(p*2+1,l,r,v);
}
t[p].v=t[p*2].v^t[p*2+1].v;
}
int ask(int p,int l,int r)
{
if(l<=t[p].l&&r>=t[p].r)
{
return t[p].v;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
int va=0;
if(l<=mid)
{
va^=ask(p*2,l,r);
}
if(r>mid)
{
va^=ask(p*2+1,l,r);
}
return va;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(h.find(a[i])!=h.end())
{
nx[h[a[i]]]=i;
}
else
{
v[i]=true;
}
h[a[i]]=i;
s[i]=s[i-1]^a[i];
}
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>q[i].l>>q[i].r;
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
build(1,1,n);
int cur=0;
for(int i=1;i<=n;i++)
{
if(v[i])
{
cur^=a[i];
}
change(1,i,i,cur);
}
int p=1;
for(int i=1;i<=m;i++)
{
while(q[i].l>p)
{
if(!nx[p])
{
nx[p]=n+1;
}
change(1,p,nx[p]-1,a[p]);
p++;
}
ans[q[i].id]=s[q[i].r]^s[q[i].l-1]^ask(1,q[i].r,q[i].r);
}
for(int i=1;i<=m;i++)
{
cout<<ans[i]<<"\n";
}
return 0;
}