CF365D-区间内出现偶数次的数的异或和

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;
}
posted @ 2024-03-25 00:38  yoshinow2001  阅读(1)  评论(0编辑  收藏  举报