617E - XOR and Favorite Number

本文介绍了一种使用莫队算法处理区间查询问题的方法。通过将数列进行前缀异或和预处理,并利用统计块内值出现次数的方式,解决了查询a[l-1]^a[r]是否等于k的问题。文章详细展示了如何在移动左右边界时更新查询答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

莫队,用统计每个块内每个值出现了几次。
对数列进行前缀异或和,每个查询因此相当于问a[l-1]^a[r]是否为k。
因此l移动时统计a[l-1]^k出现的次数,r移动时统计a[r]^k出现的次数。
没了。
傻逼一样不知道调些什么。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pll pair<LL,LL>
#define mkp make_pair
#define X first
#define Y second
#define N 100005
#define inf 2000005
struct QUERY{int L,R,wz;}qu[N];
int n,m,k,a[N],s,t,mo[N],cnt[inf];
LL ans[N],now;
int read(){
	int x=0;char ch=G;
	for(;ch<48||ch>57;ch=G);
	for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
	return x;
}
bool cmp(QUERY x,QUERY y){
	return mo[x.L]==mo[y.L]?x.R<y.R:mo[x.L]<mo[y.L];
}
int main(){
	int i,l,r;
	n=read();m=read();k=read();
	s=ceil(sqrt(n));
	rep(i,1,n)mo[i]=t+=i%s==1,a[i]=read()^a[i-1];
	rep(i,1,m){
		l=read();r=read();qu[i]=(QUERY){l,r,i};
	}
	sort(qu+1,qu+m+1,cmp);
	l=r=qu[1].L;now=k==(a[l-1]^a[r]);
	rep(i,1,m){
		while(r<qu[i].R){
			++cnt[a[r++]];
			now+=cnt[a[r]^k];
			if((a[l-1]^a[r])==k)++now;
		}
		while(r>qu[i].R){
			now-=cnt[a[r]^k];
			if((a[l-1]^a[r])==k)--now;
			--cnt[a[--r]];
		}
		while(l>qu[i].L){
			++cnt[a[--l]];
			now+=cnt[a[l-1]^k];
			if((a[l-1]^a[r])==k)++now;
		}
		while(l<qu[i].L){
			now-=cnt[a[l-1]^k];
			if((a[l-1]^a[r])==k)--now;
			--cnt[a[l++]];
		}
		ans[qu[i].wz]=now;
	}
	rep(i,1,m)printf("%lld\n",ans[i]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值