BZOJ5301: [Cqoi2018]异或序列(莫队)

5301: [Cqoi2018]异或序列

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 400  Solved: 291
[Submit][Status][Discuss]

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有多少组。

Input

输入文件第一行,为3个整数n,m,k。
第二行为空格分开的n个整数,即ai,a2,….an。
接下来m行,每行两个整数lj,rj,表示一次查询。
1≤n,m≤105,O≤k,ai≤105,1≤lj≤rj≤n

Output

输出文件共m行,对应每个查询的计算结果。

Sample Input

4 5 1
1 2 3 1
1 4
1 3
2 3
2 4
4 4

Sample Output

4
2
1
2
1

没什么说的,注意右区间操作时,要考虑左边的前缀。

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
struct in{int l,r,g,id;}s[maxn];
bool cmp(in w,in v){if(w.g!=v.g) return w.g<v.g; return w.r<v.r;}
int sum[maxn],cnt[maxn]; long long ans[maxn];
int main()
{
    int N,M,K,L,R,B,res;
    scanf("%d%d%d",&N,&M,&K); B=sqrt(N);
    for(int i=1;i<=N;i++) scanf("%d",&sum[i]),sum[i]^=sum[i-1];
    L=1; R=res=0;
    for(int i=1;i<=M;i++){
        scanf("%d%d",&s[i].l,&s[i].r);
        s[i].id=i; s[i].g=s[i].l/B;
    }
    sort(s+1,s+M+1,cmp);
    for(int i=1;i<=M;i++)
    {
        while(R<s[i].r) cnt[sum[++R]]++,res+=cnt[sum[R]^K]+((sum[R]^K)==sum[L-1]);
        while(R>s[i].r) res-=cnt[sum[R]^K]+((sum[R]^K)==sum[L-1]),cnt[sum[R--]]--;
        while(L<s[i].l) res-=cnt[sum[L-1]^K],cnt[sum[L++]]--;
        while(L>s[i].l) cnt[sum[--L]]++,res+=cnt[sum[L-1]^K];
        ans[s[i].id]=res;
    }
    for(int i=1;i<=M;i++) printf("%lld\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hua-dong/p/9964909.html