bzo5301 [Cqoi2018]异或序列 莫队

Description


已知一个长度为 n 的整数数列 a[1],a[2],…,a[n] ,给定查询参数 l、r ,问在 [l,r] 区间内,有多少连续子
序列满足异或和等于 k 。
也就是说,对于所有的 x,y (l≤x≤y≤r),能够满足a[x]^a[x+1]^…^a[y]=k的x,y有多少组。

1≤n,m≤105,O≤k,ai≤105,1≤lj≤rj≤n

Solution


没有修改而且n、m不大,考虑离线然后莫队
注意到一段连续的异或和可以拆成异或前缀和上的两个点,那么我们在成功把区间问题变成两点问题后就能愉快地用桶维护出现的异或值了

这题有点裸啊

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

const int N=200005;
const int B=250;

struct Q {int l,r,id;} q[N];

int bct[N],ans[N],a[N];
int n,m,k,sum;

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void change(int x,int v) {
    if (v==1) {
        bct[x]+=1;
        sum+=bct[x^k];
    } else {
        sum-=bct[x^k];
        bct[x]-=1;
    }
}

bool cmp(Q a,Q b) {
    return (a.l/B)<(b.l/B)||(a.l/B)==(b.l/B)&&(a.r<b.r);
}

int main(void) {
    n=read(),m=read(),k=read();
    rep(i,1,n) a[i]=a[i-1]^read();
    rep(i,1,m) {
        q[i]=(Q) {read()-1,read(),i};
    }
    std:: sort(q+1,q+m+1,cmp);
    for (int i=1,l=1,r=0;i<=m;i++) {
        for (;r<q[i].r;) change(a[++r],1);
        for (;r>q[i].r;) change(a[r--],-1);
        for (;l<q[i].l;) change(a[l++],-1);
        for (;l>q[i].l;) change(a[--l],1);
        ans[q[i].id]=sum;
    }
    rep(i,1,m) printf("%d\n", ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/81070615