D. Mishka and Interesting sum

题目链接
大致意思就是给你n个数m个操作,然后问每个操作l到r区间内出现偶数次的数的异或和.
从别人的博客里面找到的这个题,很不错。。。
思路就是离线+树状数组。
树状数组维护些什么呢,维护l 到 r区间内每个数的异或和,除此之外我们还要求出一个前缀异或和。
我们知道一个数如果异或偶数次的话那么它就会变为零,所以如果一个数出现了偶数次,那么在l到r这段异或前缀和中这个数就消失了,留下来的就是出现奇数次的异或和,而我们之前用树状数组维护了l 到r的所有数的异或和(并不是所有数例如 2 2 2 2 3 4 5 我们就维护的是 2 3 4 5 每个数出现一次的异或和) 然后用它异或上前缀和就可以得到 偶数次的异或和 因为前缀和留下来的是奇数次的数异或在一起,在异或上每个数那么奇数次的数就会消失例如上面那个例子 我们的前缀和其实是 3^ 4^ 5 而我们用树状数组维护出2 ^ 3 ^ 4 ^ 5两个数再异或一次就得出了偶数次的数的异或值即2
代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000000;
int a[1000004];
int sum1[1000004];
int pre[1000004];
void add(int x,int y){
    int num = 0;
    while(x <= maxn){
        sum1[x] ^= y;
        x += x&(-x);
    }
}

int sum(int x){
    int res = 0;
    while(x){
        res ^= sum1[x];
        x -= x&(-x);
    }
    return res;
}
map<int , int > vis;
struct node{
    int x,y;
    int id;
}T[maxn];
bool cmp(node a, node b){
    return a.y < b.y;
}
int ans[maxn];
int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++){
        cin >> a[i];
        pre[i] = pre[i - 1]^a[i];
    }
    int q;
    cin >> q;
    for(int i = 0; i < q ;i ++){
        node &a = T[i];
        cin >> a.x >>a.y;
        a.id = i;
    }
    //离线 顾名思义就是将所有问题先存下来 一个一个处理 最后再统一输出
    sort(T , T + q ,cmp);
    int j = 1;//注意要从1开始 直接从l开始会超时
    for(int i = 0; i < q; ){
        for(; j <= T[i].y; j ++){

            if(vis[a[j]] > 0){//之前出现过的,现在原来的位置上消除掉它对后面的影响
                add(vis[a[j]], a[j]);
                add(j, a[j]);//再从当前位置向后异或
                vis[a[j]] = j;
            }
            else{
                add(j, a[j]);
                vis[a[j]] = j;
            }
        }

        ans[T[i].id] = sum(T[i].y)^sum(T[i].x - 1)^pre[T[i].y]^pre[T[i].x- 1];//求出所有答案

        i ++;
    }
    for(int i = 0; i < q; i ++){
        cout << ans[i] <<" ";
    }
    cout << endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值