菠萝蜜多斩(离散排序+树状数组)

波罗蜜多斩

url:C-菠萝蜜多斩_浙江广厦大学第七届程序设计比赛 (nowcoder.com)

Problem:

给定一个数组,求出我所给定范围的所有偶数个的异或值

Ideas:

标签: 离散排序+树状数组

**思路:**query存储所有出现过的数字的异或值,sum存储所有奇数个的数字的异或值 ,那么二者区间的异或值就是出现次数为偶数的异或值了

sum很好求,直接前缀和思路即可

树状数组这边用到的离散化的作用是将下标表示出来,不然last[a[i]],a[i]过大last容量不够


sum很好理解,query可以这么理解

用树状数组去存储所有出现过某个数的异或值,如 1 2 3 4 2,第一个2可以对后面的都产生影响,那么数组下标从2~5均应该出现与2的异或值,此时看第二个2,他的出现由于是异或会产生抵消的效果,但是由于右区间来到了i = 5的位置,那么前面出现的2(也同样是i = 2)到该2(i = 4) 中间这一段可以被认为没有2的异或值了,这么做可以让区间(L ,5) 一定有2的异或值【抵消的作用】,否则没有清除的话【L(L>=2), 5】就不存在2的异或值,但是2又出想过

for (int i = 1 ; i <= n ; i++) {
    if (last[a[i]] != 0) {  
    	add(last[a[i]], idx[a[i]]);
    }
    last[a[i]] = i;
    add(i, idx[a[i]]);
    for (auto &[L, idx] : vec[i]) {
    	ans[idx] = query(i) ^ query(L - 1) ^ sum[i] ^ sum[L - 1];
    }
}

Code:

#include <bits/stdc++.h>
//#define int long long
#define endl "\n"

using namespace std;

const int N = 1000000 + 10;

typedef pair<int, int> PII;

int n, m;
int a[N], tr[N];
int sum[N];

int lowbit(int x) {
    return x & -x;
}

void add(int x, int k) {
    for(int i = x; i <= n; i += lowbit(i)) tr[i] ^= k;
}

int query(int x) {
    int res = 0;
    for(int i = x; i; i -= lowbit(i)) res ^= tr[i];
    return res;
}

void solve() {
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] ^ a[i];
    int b[N];
    for(int i = 1; i <= n; i++) b[i] = a[i]; 
    vector<PII> v[N];
    for(int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        v[y].push_back({x, i});
    }
    sort(b + 1, b + 1 + n);
    map<int, int> mp;
    int k = 1;
    int c[N];
    for(int i = 1; i <= n; i++) {
        if(i == 1 || b[i] != b[i - 1]) mp[b[i]] = k, c[k++] = b[i];
    }

    for(int i = 1; i <= n; i++) a[i] = mp[a[i]];
    int last[N] = {0};
    int ans[N];
    for(int i = 1; i <= n; i++) {
        if(last[a[i]]) {
            add(last[a[i]], c[a[i]]);
        }
        last[a[i]] = i;

        add(i, c[a[i]]);
        for(auto A : v[i]) {
            ans[A.second] = query(i) ^ query(A.first - 1) ^ sum[i] ^ sum[A.first - 1];
        }
    }

    for(int i = 1; i <= m; i++) cout << ans[i] << endl;
}

signed main()
{
    ios::sync_with_stdio(false), cin.tie(0);
    cout.tie(0);
    
    int t = 1;
    //cin >> t;
    while(t--) {
    	solve();
    }
}
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值