莫队算法 CF617E 区间异或=k的区间个数

思路:
如何求出任意一段的区间异或值是个问题。

如果a[i] ^ a[i+1] ^ … ^ a[j] = k 相当于 s[i-1]^s[j]==k, s[]为异或前缀和,那么就是求一个区间的前缀和s[i] ^ s[j]的对数。

莫队转移一下就行了。

WA点:区间前缀和可以比k大, 保存前缀和的数字应该开大一点。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//由块号寻找第一个块元素的下标
#define LL(x) ((x-1)*Len+1)

const int maxn=1<<20;

struct node
{
    int L, R, k;
}q[maxn];

int pos[maxn];
LL ans[maxn];
LL flag[maxn];//保存当前区间前缀和的个数
int a[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 n, m, k, Len;
int L=1, R=0;
LL ANS=0;

void add(int x)
{
    //先加防止 a[x]^k==a[x] 重复加上
    ANS+=flag[a[x]^k];
    flag[a[x]]++;
}

void del(int x)
{
    //先减防止 a[x]^k==a[x] 重复减去
    flag[a[x]]--;
    ANS-=flag[a[x]^k];
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    Len=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        a[i]=a[i]^a[i-1];
        pos[i]=i/Len;
    }

    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&q[i].L,&q[i].R);
        q[i].k=i;
    }

    sort(q+1, q+1+m, cmp);
    flag[0]=1;//为了统计a[i]=k

    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].k]=ANS;
    }
    for(int i=1;i<=m;i++)
    {
        cout<<ans[i]<<endl;
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值