E. XOR and Favorite Number(莫队异或)

题目描述

题目链接

给定一个长度为 n 的序列 a,然后再给一个数字 k,再给出 m 组询问,每组询问给出一个区间,求这个区间里面有多少个子区间的异或值为 k

1n,m10^5,0k,ai10^6,1lirin

题目思路

要做这个题首先要知道两个性质

1.异或前缀和

2.a^b=x则a^x=b

1.处理出异或前缀和数组a[i]^=a[i-1];
2.对于区间[L,R]的异或和,即为a[R]^a[L-1]
3.如果x ^ y=k,那么x=k ^ y
对于一个区间[L,R],我们维护[L-1,R]的异或前缀和.
当加入新元素时a[x],如果在我们维护的前缀和里存在a[x]^k,那么就会对答案产生贡献.
注意这个题左端点是L-1,这是关键!

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=5e6+100;
ll a[maxn],ans[maxn];
const int block=313;
struct node{
    int l,r,id;
    bool friend operator<(node x,node y){
        if(x.l/block!=y.l/block){
            return x.l/block<y.l/block;
        }
        else{
            if((x.l/block)&1){
                return x.r>y.r;
            } 
            else{
                return x.r<y.r;
            }
        }
    }
}q[maxn];
ll cnt[maxn];
ll tot=0;
int n,m;
ll k;
inline void add(int p)
{
    tot+=cnt[k^a[p]];
    cnt[a[p]]++;
}
inline void del(int p)
{
    cnt[a[p]]--;//要先减减
    tot-=cnt[k^a[p]];
}
int main(){
    scanf("%d%d%lld",&n,&m,&k);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        a[i]^=a[i-1];    
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].l--;
        q[i].id=i;
    }
    sort(q+1,q+m+1);
    int ql=q[1].l,qr=q[1].r;
    for(int i=ql;i<=qr;i++){
        add(i);
    }
    ans[q[1].id]=tot;
    for(int i=2;i<=m;i++){
        while(ql<q[i].l){
            del(ql);
            ql++;
        } 
        while(qr>q[i].r){
            del(qr);
            qr--;
        }
        while(ql>q[i].l){
            ql--;
            add(ql);
        }
        while(qr<q[i].r){
            qr++;
            add(qr);
        }
        ans[q[i].id]=tot;
    }
    for(int i=1;i<=m;i++){
        cout<<ans[i]<<"\n";
    }
    
}

 

 

 

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=5e6+100;
ll a[maxn],ans[maxn];
const int block=313;
struct node{
    int l,r,id;
    bool friend operator<(node x,node y){
        if(x.l/block!=y.l/block){
            return x.l/block<y.l/block;
        }
        else{
            if((x.l/block)&1){
                return x.r>y.r;
            } 
            else{
                return x.r<y.r;
            }
        }
    }
}q[maxn];
ll cnt[maxn];
ll tot=0;
int n,m;
ll k;
inline void add(int p)
{
    tot+=cnt[k^a[p]];
    cnt[a[p]]++;
}
inline void del(int p)
{
    cnt[a[p]]--;
    tot-=cnt[k^a[p]];
}
int main(){
    scanf("%d%d%lld",&n,&m,&k);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        a[i]^=a[i-1];    
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].l--;
        q[i].id=i;
    }
    sort(q+1,q+m+1);
    int ql=0,qr=0;
    cnt[a[0]]=1;
    for(int i=1;i<=m;i++){
        while(ql<q[i].l){
            del(ql);
            ql++;
        } 
        while(qr>q[i].r){
            del(qr);
            qr--;
        }
        while(ql>q[i].l){
            ql--;
            add(ql);
        }
        while(qr<q[i].r){
            qr++;
            add(qr);
        }
        ans[q[i].id]=tot;
    }
    for(int i=1;i<=m;i++){
        cout<<ans[i]<<"\n";
    }
    
}

 

posted @ 2021-08-11 14:19  lipu123  阅读(72)  评论(0)    收藏  举报