Mishka and Interesting sum

Mishka and Interesting sum

题意:查询区间中出现偶数次的数的异或和
 
树状数组
 
若是求奇数次的数的异或和,很好求区间[l,r]的异或和,即前r项异或和与前l-1项异或和异或即可
 
但这要求偶数次的,想办法把偶数的转化成奇数的,即区间中出现奇数次的异或和与不同数的异或和 异或 即可
 
出现的奇数次的异或和写前缀数组解决,不同数的用树状数组优化,用一个map映射my[x]表示x的上一步的位置
 
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>

using namespace std;
const int N=1e6+9;
int c[N],a[N],pre[N],n;

struct P{
    int l,r,ant,sub;
}ans[N];
int cmp(P x,P y)
{
    return x.r<y.r;
}
int cmp1(P x,P y)
{
    return x.sub<y.sub;
}
int lowbit(int x)
{
    return x&(-x);
}
void updata(int x,int y) //单点修改
{
    int i=x;
    while(i<=n)
    {
        c[i]^=y;
        i+=lowbit(i);
    }
}
int query(int x) //前x项求异或和
{
    int i=x,sum=0;
    while(i)
    {
        sum^=c[i];
        i-=lowbit(i);
    }
    return sum;
}
int main()
{
    scanf("%d",&n);
    map<int,int>my;
    my.clear();
    memset(c,0,sizeof(c));
    pre[0]=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pre[i]=pre[i-1]^a[i];
    }
    int m;
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&ans[i].l,&ans[i].r);
        ans[i].sub=i;
    }
    int p=1;
    sort(ans,ans+m,cmp);
    for(int i=0;i<m;i++)
    {
        int l=ans[i].l,r=ans[i].r;
        while(p<=r)
        {
            if(my[a[p]]==0)
            {
                my[a[p]]=p;
                updata(p,a[p]);
            }
            else
            {
                updata(my[a[p]],a[p]);
                updata(p,a[p]);
                my[a[p]]=p;
            }
            p++;
        }
        ans[i].ant=pre[r]^pre[l-1]^query(r)^query(l-1);
    }
    sort(ans,ans+m,cmp1);
    for(int i=0;i<m;i++)00
        printf("%d%c",ans[i].ant,i==m-1?'\n':' ');
    return 0;
}
View Code

 

 
 
 
posted @ 2018-01-25 20:57  jadelemon  阅读(188)  评论(0编辑  收藏  举报