Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum(思维+差分)

题目链接
大意:给你一个序列,给出询问l,r区间,让你写输出现偶数次的数的异或和

思路:显然区间直接的异或和是出现奇数次的数的异或和,那我们要求的是偶数次的,显然我们只需一步,把区间所有出现过的数再异或起来,两个的异或和就是答案了,因为这样做,出现奇数次的数就会被去掉剩下的就是偶数次的数了。。。。
那么问题就转化为区间只出现过一次的数的异或和。
先把序列离散话一下。
考虑按r从小到大离线查询。。。
维护每个数出现的上个位置。然后显然 p r e + 1 n o w pre+1-now 都是需要把当前的值加上的,那我们直接维护异或和差分即可,每个询问的左端点显然就是整个询问区间的出现过的数的异或和,再和整个区间的异或和 异或起来就是这个询问的答案了。
细节见代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
#define fi first
#define se second
#define pb push_back
int f[N],n,a[N];
struct uzi{
    int l,r,i;
    bool operator <(const uzi &t)const{
        if(r==t.r)return l<t.l;
        return r<t.r;
    }
}p[N];
int c[N];
int pre[N];
int t[N];
void add(int p,LL d){
    for(int i=p;i<=n;i+=(i&-i))t[i]^=d;
}
int get(int p){
    int ans=0;
    for(int i=p;i;i-=(i&-i))ans^=t[i];
    return ans;
}
int ans[N];
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),f[i]=(a[i]^f[i-1]),c[i]=a[i];
    int m;
    scanf("%d",&m);
    sort(c+1,c+1+n);
    int len=unique(c+1,c+1+n)-c-1;
    for(int i=1;i<=n;i++)a[i]=lower_bound(c+1,c+1+len,a[i])-c;
    for(int i=1;i<=m;i++)scanf("%d%d",&p[i].l,&p[i].r),p[i].i=i;
    sort(p+1,p+1+m);
    int l=1;
    for(int i=1;i<=m;i++){
        while(l<=p[i].r){
            add(pre[a[l]]+1,c[a[l]]);
            add(l+1,c[a[l]]);
            pre[a[l]]=l;
            l++;
        }
        int tmp=get(p[i].l);
        tmp^=(f[p[i].r]^f[p[i].l-1]);
        ans[p[i].i]=tmp;
    }
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}
发布了160 篇原创文章 · 获赞 81 · 访问量 9677

猜你喜欢

转载自blog.csdn.net/qq_40655981/article/details/102938354