题意:
给出序列a1,a2,a3......an,有m次形如[L,R]的提问,对于每次提问:
输出在aL......aR这些数中出现了偶数次的所有数的异或起来的结果。
The first line of the input contains single integer n (1 ≤ n ≤ 1 000 000) — the number of elements in the array.
The second line of the input contains n integers a1, a2, ..., an (1 ≤ ai ≤ 109) — array elements.
The third line of the input contains single integer m (1 ≤ m ≤ 1 000 000) — the number of queries.
Each of the next m lines describes corresponding query by a pair of integers l and r (1 ≤ l ≤ r ≤ n) — the bounds of query segment.
Print m non-negative integers — the answers for the queries in the order they appear in the input.
3 3 7 8 1 1 3
0
7 1 2 1 3 3 2 3 5 4 7 4 5 1 3 1 7 1 5
0 3 1 3 2
分析:
对于区间[L,R]:
设XOR_SUM是[L,R]中所有数的"异或和",SUM表示[L,R]中出现过的数字的“异或和”。
容易发现:ANS=SUM^XOR_SUM.
问题也就变成了求SUM([L,R]中出现过的数字的“异或和”)。
在线算法没有想出来,考虑一下离线:
将提问的区间按左端点排序,先暴力求出形如[1,R]提问的所有答案,存在SUM[]中。
记Next[i]表示和i这个数相同的下一个位置。
如果现在询问变成了[2,R],在a1这个数再次出现以前(Next[a1]),SUM[1]~SUM[Next[a1]-1]这一段都要去掉a1这个数,区间修改。
答案就是点查询。
代码中sum和lazy标记共用了一个数组,代码如下:
#include<cstdio> #include<iostream> #include<cstring> #include<map> #include<algorithm> using namespace std; const int maxn=1000000+5; int n,m,s[maxn],Next[maxn],xor_sum[maxn],ans[maxn]; map<int,int> fst; map<int,bool> vis; int y1,y2,val[maxn],sum[maxn<<3]; inline void _read(int &x){ char ch=getchar(); bool mark=false; for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true; for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0'; if(mark)x=-x; } struct Query{ int L,R,id; bool operator < (const Query s)const { return L<s.L; } }ask[maxn]; void build(int o,int L,int R){ if(L==R)sum[o]=val[L]; else { int mid=(L+R)>>1; build(o*2,L,mid); build(o*2+1,mid+1,R); } } void pushdown(int o){ int ls=o<<1,rs=ls+1; sum[ls]^=sum[o]; sum[rs]^=sum[o]; sum[o]=0; } void update(int o,int L,int R,int v){ if(sum[o]&&L!=R)pushdown(o); if(y1<=L&&y2>=R) sum[o]^=v; else { int mid=(L+R)>>1; if(y1<=mid)update(o<<1,L,mid,v); if(y2>mid) update(o*2+1,mid+1,R,v); } } int query(int o,int L,int R,int p){ if(sum[o]&&L!=R)pushdown(o); if(L==R) return sum[o]; else { int mid=(L+R)>>1; if(p<=mid) return query(o<<1,L,mid,p); else return query(o*2+1,mid+1,R,p); } } int main(){ _read(n); int i,x; for(i=1;i<=n;i++){ _read(s[i]); val[i]=val[i-1]; if(!vis[s[i]]){ //暴力求出[1,R]的答案 vis[s[i]]=true; val[i]^=s[i]; } xor_sum[i]=xor_sum[i-1]^s[i]; } for(i=n;i>0;i--) Next[i]=fst[s[i]],fst[s[i]]=i; build(1,1,n); _read(m); for(i=1;i<=m;i++){ _read(ask[i].L); _read(ask[i].R); ask[i].id=i; } sort(ask+1,ask+1+m); int cur=1; for(i=1;i<=m;i++){ while(cur<ask[i].L){ if(!Next[cur])Next[cur]=n+1; y1=cur; y2=Next[cur]-1; update(1,1,n,s[cur]); cur++; } y1=ask[i].L; y2=ask[i].R; ans[ask[i].id]=query(1,1,n,y2)^xor_sum[y2]^xor_sum[y1-1]; } for(i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
<pre name="code" class="cpp">#include<iostream> #include<cstdio> #include<map> #include<algorithm> using namespace std; const int maxn=1000005; int sum1[maxn],sum2[maxn]; int a[maxn]; int n,m; map<int,bool>mark; map<int,int>last; int _next[maxn]; //sum1 chuxian //sum2 suoyou struct node2{ int l,r,id,ans; }; node2 query[maxn]; bool cmp(node2 a,node2 b){ if(a.l==b.l)return a.r<b.r; else return a.l<b.l; } bool cmp2(node2 a,node2 b){ return a.id<b.id; } struct node{ int a,b,lazy; }; node tree[maxn<<2]; void build_tree(int p,int x,int y){ tree[p].a=x;tree[p].b=y; if(x<y){ int mid=(x+y)>>1; build_tree((p<<1),x,mid); build_tree((p<<1)+1,mid+1,y); } else{ tree[p].lazy=sum1[x]; } } void putdown(int p){ int ls=(p<<1),rs=(p<<1)+1; tree[ls].lazy^=tree[p].lazy; tree[rs].lazy^=tree[p].lazy; tree[p].lazy=0; } void change(int p,int x,int y,int d){ if(tree[p].b<x||tree[p].a>y)return; if(tree[p].a<tree[p].b&&tree[p].lazy)putdown(p); if(x<=tree[p].a&&tree[p].b<=y){ tree[p].lazy^=d; return; } change((p<<1),x,y,d); change((p<<1)+1,x,y,d); } int getans(int p,int r){ //if(tree[p].b<r||tree[p].a>r)return; if(tree[p].a<tree[p].b&&tree[p].lazy)putdown(p); if(tree[p].a==tree[p].b){ return tree[p].lazy; } if(tree[p<<1].a<=r&&tree[p<<1].b>=r)getans((p<<1),r); else if(tree[(p<<1)+1].a<=r&&tree[(p<<1)+1].b>=r)getans((p<<1)+1,r); } int main(){ int i,j,k; cin>>n; for(i=1;i<=n;i++){ scanf("%d",&a[i]); if(mark[a[i]]==false){ sum1[i]=sum1[i-1]^a[i]; mark[a[i]]=true; } else sum1[i]=sum1[i-1]; sum2[i]=sum2[i-1]^a[i]; } build_tree(1,1,n); for(i=n;i;i--){ _next[i]=last[a[i]]; last[a[i]]=i; } cin>>m; for(i=1;i<=m;i++){ scanf("%d%d",&query[i].l,&query[i].r); query[i].id=i; } sort(query+1,query+1+m,cmp); int l=1; for(i=1;i<=m;i++){ while(l<query[i].l){ if(_next[l]==0)_next[l]=n+1; change(1,l,_next[l]-1,a[l]); l++; } query[i].ans=getans(1,query[i].r)^sum2[query[i].r]^sum2[query[i].l-1]; } sort(query+1,query+1+m,cmp2); for(i=1;i<=m;i++){ printf("%d\n",query[i].ans); } }