link:https://codeforces.com/contest/703/problem/D
題意: 給一個序列 \(a_1,\dots,a_n\),有 \(m\) 次詢問,每次問一段區間 \([l,r]\) 內出現偶數次的數的異或和,\(1\leq n,m\leq 10^6\)。
偶數次異或和=區間異或和 xor 區間內所有元素只算一次的異或和
這個問題可以有挺多思考的:比如先考慮另一個問題,區間內有多少種不同的數字,常見方法就是記一個 \(lst(x)\) 表示上一次出現位置,如果可以離線就對詢問排序(如按右端點),按住右端點,對序列維護一個 \(c_i\) ,如果 \(i\) 是 \(a_i\) 最後一次出現,則 \(c_i=1\),否則 \(c_i=0\),回答不同的數個數就是回答區間和。如果強制線上則考慮每個數 \(a_i\) 在區間 \([l,r]\) 內第一次出現的地方統計,則其上一次出現位置 \(lst(i)<l\) ,處理出 \(lst\) 陣列,對區間維護一個可持久化線段樹,把 \(lst\) 打到值域上,就變成了求字首和。
回到這個問題,稍微修改一下就好。
實現的時候注意想清楚,需要的是區間求異或和,以及單點修改(賦值),所以用一個樹狀陣列就夠了。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int N=1e6+5;
struct Query{int l,r,idx;};
struct Fenwick{
int lowbit(int x){return x&-x;}
int tr[N],n;
int query(int x){
int ret=0;
for(;x;x-=lowbit(x))ret^=tr[x];
return ret;
}
void modify(int x,int v){
for(;x<=n;x+=lowbit(x))tr[x]^=v;
}
}pre;
int n,m,a[N],s[N],ans[N];
map<int,int> lst;
vector<vector<Query>> Q;
int main(){
fastio;
cin>>n;
rep(i,1,n){
cin>>a[i];
s[i]=(s[i-1]^a[i]);
}
cin>>m;
Q=vector<vector<Query>>(n+1);
rep(i,1,m){
int l,r;cin>>l>>r;
Q[r].push_back({l,r,i});
}
pre.n=n;
rep(i,1,n){
pre.modify(i,a[i]);
if(lst.count(a[i]))pre.modify(lst[a[i]],a[i]);
lst[a[i]]=i;
for(auto [l,r,idx]:Q[i])
ans[idx]=(s[r]^s[l-1]^pre.query(r)^pre.query(l-1));
}
rep(i,1,m)cout<<ans[i]<<endl;
return 0;
}