XOR and Favorite Number题解

发布时间 2023-09-04 17:03:37作者: 铃狐sama

XOR and Favorite Number题解

思路引导

这一道题主要是为了说明莫队算法和分块之间的联系。
先主要讲讲莫队的用处吧。
它是个离线算法,维护两个指针l,r。
移动l和r的时候顺便进行更改,维护好l-r区间内的某个值。
对于询问区间的排序,遵循l所在的分块相同,其次是r的先后顺序。

现在来说说本题:
关键在于莫队维护什么
我加入一个数p时,我就知道了他的亦或前缀和。
那现在我想要在这个区间内找到有多少个抑或前缀和与之抑或后为k。
这个区间指的是l到p这个区间。
显然k已知,那么这个抑或前缀和也已知,只需要知道这个东西出现的次数就好啦。
稍微注意一下l的-1问题即可。

代码实现:

#include<bits/stdc++.h>
using namespace std;
#define int long long
/*
关键在于莫队维护什么
我加入一个数p时,我就知道了他的亦或前缀和。
那现在我想要在这个区间内找到有多少个抑或前缀和与之抑或后为k。
这个区间指的是p+1到r这个区间。
显然k已知,那么这个抑或前缀和也已知,只需要知道这个东西出现的次数就好啦。
*/
#define ingrp(x) ceil(1.0*x/sq)
int sq,n,m,k;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9')
        x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline void write(int x)
{
    if(x<0)
        putchar('-'),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
    return;
}

int num[100005];
int pre[100005];
struct nod{
    int le;
    int ri;
    int id;
}line[100005];
int ans[100005];
int cnt[2000006];

int sum,l,r;
void add(int x){
    sum+=cnt[pre[x]^k];
    cnt[pre[x]]++;
}
void del(int x){
    cnt[pre[x]]--;
    sum-=cnt[pre[x]^k];
}
bool cmp(nod x,nod y){
    int x1=ingrp(x.le);
    int x2=ingrp(y.le);
    if(x1!=x2){
        return x1<x2;
    }
    else return x.ri<y.ri;
}
void mvftL(int goal){
    while(l-1>=goal){
        add(l-1);
        l--;
    }
}
void mvbkL(int goal){
    while(l+1<=goal){
        del(l);
        l++;
    }
}
void mvftR(int goal){
    while(r-1>=goal){
        del(r);
        r--;
    }
}
void mvbkR(int goal){
    while(r+1<=goal){
        add(r+1);
        r++;
    }
}
signed main(){
    n=read();
    sq=floor(1.0*sqrt(n));
    m=read();
    k=read();
    for(int i=1;i<=n;i++){
        num[i]=read();
        pre[i]=pre[i-1]^num[i];
    }
    for(int i=1;i<=m;i++){
        line[i].le=read();
        line[i].le--;
        line[i].ri=read();
        line[i].id=i;
    }
    sort(line+1,line+1+m,cmp);
    add(line[1].le);
    l=line[1].le;
    r=line[1].le;
    for(int i=1;i<=m;i++){
        int ll=line[i].le;
        int rr=line[i].ri;
        int id=line[i].id;
        mvftL(ll);
        mvbkL(ll);
        mvftR(rr);
        mvbkR(rr);
        ans[id]=sum;
    }
    for(int i=1;i<=m;i++){
        cout<<ans[i]<<endl;
    }

}