Codeforces Round #340 (Div. 2)E

区间莫队+异或前缀和

假设p[i]表示a[1]^a[2]....a[i]

那么

a[i]^a[i+1]....^a[j]=p[j]^p[i-1]

对于每一个新增的询问a[x],增加的个数为a[x]^k出现的数目

代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#define ll long long 
using namespace std;
const int maxn=1<<20;
ll flag[maxn];//存每一个前缀抑或出现次数
int a[maxn];//存放异或前缀和 
ll ans[maxn];//存放答案 
int pos[maxn];//存放区间 
struct node
{
    int l,r,id;
}Q[maxn];
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];
}
int L=1,R=0;
ll Ans=0;
int n,m,k;
void add(int x)
{
    Ans+=flag[a[x]^k];
    flag[a[x]]++;
}
void del(int x)
{
    flag[a[x]]--;
    Ans-=flag[a[x]^k];
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int block=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        //scanf("%d",&a[i]);
        cin>>a[i];
        a[i]=a[i]^a[i-1];
        pos[i]=i/block;
    }
    for(int i=1;i<=m;i++)
    {
        //scanf("%d%d",&Q[i].l,&Q[i].r);
        cin>>Q[i].l>>Q[i].r;
        Q[i].id=i;
    }
    sort(Q+1,Q+1+m,cmp);
    flag[0]=1;
    for(int i=1;i<=m;i++)
    {
        while(L<Q[i].l)
        {
            del(L-1);
            L++;
        }
        while(L>Q[i].l)
        {
            L--;
            add(L-1);
        }
        while(R<Q[i].r)
        {
            R++;
            add(R);
        }
        while(R>Q[i].r)
        {
            del(R);
            R--;
        }
        ans[Q[i].id]=Ans;
    }
    for(int i=1;i<=m;i++)
    printf("%lld
",ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/flyljz/p/11700081.html