CodeForces 703D Mishka and Interesting sum (树状数组处理异或和)

题意:求区间上出现偶数次的数 的异或和。


分析: 如果求出现奇数次的数 的异或和,则只需预处理前缀异或和,然后马上就能求出来了。一个数异或偶数次为0。

            所以这题把问题简单化,把偶数次变奇数次,奇数次变偶数次。(主要思想)

           1. 预处理前缀异或和(偶数次被异或没了)

           2.pre数组记录当前数上一次出现的位置,没出现过则为0

           3.先把查询记录下来,按右端点排序,方便后面查询,具体看代码。

           4.将元素一个个按位置加进树状数组,如果这个数前面出现过,则在上一次出现的位置异或下这个数,然后再在当前位置加入这个数(相当于把偶数次变奇数次)。

             简单说就是求区间所有数的异或和(去掉重复的)。

          5.这个区间的前缀异或和 异或 区间所有数的异或和(去掉重复的)得到结果。

            这一步是去除区间出现奇数次的数。


第一次在cf用cin cout会T,改用scanf printf  过了 题目给了3.5s    大概用了1.6s



#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const long long INF = 1e18;
const int N= 1e6+10;
const int maxn = 1e6+10;
const int maxm = 2000000001;
const int MOD = 1e6;
int A[maxn],n;
void ADD(int x, int c)
{
     for (int i=x; i<=n; i+=i&(-i)) A[i] ^= c;
}
int SUM(int x)
{
    int s = 0;
    for (int i=x; i>0; i-=i&(-i)) s ^= A[i];
    return s;
}
struct Node{
    int l,r,pos;
}qu[maxn];
map<int,int> mp;
int ans[maxn];
int sum[maxn],a[maxn],pre[maxn];
bool cmp(Node xx,Node yy)
{
    return xx.r<yy.r;
}
int main(){
#ifdef LOCAL
	freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
	//freopen("output.txt","w",stdout);
#endif
//ios_base::sync_with_stdio(0);
    scanf("%d",&n);
    sum[0] = 0;
    //mp.clear();memset(ans,0,sizeof(ans));
    for(int i = 1; i <= n; i++)
    {
        scanf("%d",&a[i]);
        sum[i] = sum[i-1]^a[i];
        pre[i] = mp[a[i]];
        mp[a[i]] = i;
    }
    int q;
    scanf("%d",&q);
    for(int i = 1; i <= q; i++)
    {
        scanf("%d%d",&qu[i].l,&qu[i].r);
        qu[i].pos = i;
    }
    sort(qu+1,qu+q+1,cmp);
    int j = 1;
    for(int i = 1; i <= q; i++)
    {
        for( ;j <= qu[i].r; j++)
        {
            if (pre[j]) ADD(pre[j],a[j]);
            ADD(j,a[j]);
        }
        ans[qu[i].pos] = sum[qu[i].r]^sum[qu[i].l-1]^SUM(qu[i].r)^SUM(qu[i].l-1);
    }
    for(int i = 1; i <= q; i++) printf("%d\n",ans[i]);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值