Codeforces617 E . XOR and Favorite Number(莫队算法)

本题是经典的莫队算法

莫队算法是离线查询的一种复杂度优秀的暴力算法。

首先我们需要注意异或的几个性质,相同数字异或等于0,所以我们考虑前缀和,因为从ai-aj的异或值就等于pre[i-1]^pre[j] 前缀和的异或,因为相同部分会抵消。

莫队一般和分块相结合,我们需要维护一个cnt数组,cnt[a[x]]表示异或结果是a[x]的值有多少,这就可以表示贡献度。

几个坑点:

1.异或值可以大于原值,所以首先要注意int,其次数组范围要开大一点

2.为什么在维护add的时候要先算贡献再加,而sub时要先减?

因为有一种特殊情况会使x^k=x,也就是k=0的时候,那么这个时候不能算这个区间,因为这是自身的匹配是空匹配,因为前缀和是pre[i-1]^pre[j],这种情况就是pre[i-1]^pre[i-1]这里面是没有值的。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1<<20;
ll ans[N];
ll cnt[N];
ll pos[N];
ll a[N];
ll res;
int n,m,k;
struct node{
    int l,r;
    int k;
}q[N];
bool cmp(node a,node b){
    if(pos[a.l]==pos[b.l])
    return a.r<b.r;
    return pos[a.l]<pos[b.l];
}
void add(int x){
    res+=cnt[a[x]^k]; //贡献 
    cnt[a[x]]++;
}
void sub(int x){
    cnt[a[x]]--;
    res-=cnt[a[x]^k];
}
int main(){
    int i;
    cin>>n>>m>>k;
    int block=sqrt(n);
    for(i=1;i<=n;i++){
        cin>>a[i];
        a[i]^=a[i-1];
        pos[i]=(i-1)/block+1;
    }
    for(i=1;i<=m;i++){
        cin>>q[i].l>>q[i].r;
        q[i].k=i;
    }
    sort(q+1,q+1+m,cmp);
    int l=1;
    int r=0;
    cnt[0]=1;
    for(i=1;i<=m;i++){
        while(q[i].l<l){
            l--;
            add(l-1);
        }
        while(q[i].r>r){
            r++;
            add(r);
        }
        while(q[i].l>l){
            sub(l-1);
            l++;
        }
        
        while(q[i].r<r){
            sub(r);
            r--;
        }
        ans[q[i].k]=res;
    }
    for(i=1;i<=m;i++)
    cout<<ans[i]<<endl; 
    
}

相关推荐