CF365D-區間內出現偶數次的數的異或和

yoshinow2001發表於2024-03-25

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;
}

相關文章