天天看点

Codeforces Round #340 (Div. 2) E XOR and Favorite NumberXOR and Favorite Number

XOR and Favorite Number

这把CF明显题风不太对,前四道一眼题,最后来个模板题。不过正好给我科普了莫队这个姿势。莫队其实更像是一种思想,而不是一个具体的算法。总结下,它能处理的问题是无修改的区间查询,方法是按总长度的平方根分块,然后将询问排序(先按左端点所属块,再按右端点),离线求解。

这道题,先预处理前缀异或结果,记为 prefix , [l,r] 的答案就是 prefix[l−1] 异或 prefix[r] 。用莫队的时候,就是将左端点固定在块内(当然每次块内移动还是要花 O(n0.5) 的时间去处理的),右端点不断往后推。总复杂度 O(n1.5) 。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

int n,m,k;
int a[];
int prefix[];

int cnt[<<];

struct query{
    int l;
    int r;
    int block;
    int id;
    bool operator<(const query &other)const{
        if(block!=other.block){
            return block<other.block;
        }
        return r<other.r;
    }
}qs[];

ll ans [];

int main(){ 
    cin>>n>>m>>k;
    for(int i=;i<=n;i++){
        scanf("%d",&a[i]);
        prefix[i] = prefix[i-]^a[i];
    }

    int SQRT = sqrt(n);

    for(int i=;i<m;i++){
        scanf("%d%d",&qs[i].l,&qs[i].r);
        qs[i].block = qs[i].l/SQRT;
        qs[i].id = i;
    }

    sort(qs,qs+m);

    int preL;
    int preR;

    ll tmp = ;
    for(int q=;q<m;q++){
        int L = qs[q].l;
        int R = qs[q].r;

        if(q== || qs[q-].block!=qs[q].block || L>preR){   //新块或者该区间和上个区间没有交集 
            memset(cnt,,sizeof(cnt));
            preL=L;
            preR=L-;
            tmp=;
            cnt[prefix[qs[q].l-]]++;
        }else{
            //块内调整左边,注意代码顺序. 
            if(L>preL){
                for(int i=preL;i<L;i++){
                    cnt[prefix[i-]]--;
                    tmp-=cnt[ prefix[i-]^k ];
                }
            }else if(L<preL){
                for(int i=preL-;i>=L;i--){
                    tmp+=cnt[ prefix[i-]^k ];
                    cnt[prefix[i-]]++;
                }
            }
            preL=L;
        }

        //右边界往后推 
        for(int i=preR+;i<=R;i++){
            tmp+=cnt[ prefix[i]^k ];
            cnt[prefix[i]]++;
        }

        preR=R;
        ans[qs[q].id] = tmp;
    }

    for(int i=;i<m;i++){
        printf("%I64d\n",ans[i]);
    }

    return ;
}
           

继续阅读