bzoj4571

    这道题的简化版是没有加d的。如果是那样的话,我们只需要做一个可持久化trie树就好了。把要异或的数划分为二进制,从高位向低位匹配,如果当前位为0,我们查询区间内的数当前位能否为1;如果当前位为1,我们查询区间内的数当前位能否为0。具体来说,假设现在已经匹配了x(这个x是拿来与b匹配的x而不是匹配后的值),现在要匹配第h位,并且b的第h位为1,我们要确定当前位能否为0,其实就是找【x,x+2^h-1】这个区间内的siz是否大于0。h位为0,同理。那么它加了一个d的话,好办,只需要把原来那个区间同时减去d就好了。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
const int M=1e6+10;
const int sz=262144;
int n,m,now,tot,ls[M],rs[M],a[N],sum[M],rt[N];
void update(int pre,int &o,int l,int r,int x){
	o=++tot;ls[o]=ls[pre];rs[o]=rs[pre];
	sum[o]=sum[pre]+1;
	if(l==r) return ;
	int mid=l+r>>1;
	if(x<mid) update(ls[pre],ls[o],l,mid,x);
	else update(rs[pre],rs[o],mid+1,r,x);
}
int query(int last,int now,int l,int r,int L,int R){
	if(l>=L&&r<=R) return sum[now]-sum[last];
	if(r<L||l>R) return 0;
	int mid=l+r>>1;
	return query(ls[last],ls[now],l,mid,L,R)+query(rs[last],rs[now],mid+1,r,L,R);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
		update(rt[i-1],rt[i],1,sz,a[i]);
	}
	for(int i=1;i<=m;++i){
		int b,d,l,r;scanf("%d%d%d%d",&b,&d,&l,&r);
		now=0;
		for(int k=17;k>=0;--k){
			if(b&(1<<k)){
				if(query(rt[l-1],rt[r],1,sz,max(0,now-d),max(0,now+(1<<k)-1-d))<=0)
				if(query(rt[l-1],rt[r],1,sz,max(0,now+(1<<k)-d),max(0,now+(1<<(k+1))-1-d))>0) now+=1<<k;
			}else{
				if(query(rt[l-1],rt[r],1,sz,max(0,now+(1<<k)-d),max(0,now+(1<<(k+1))-1-d))>0) now+=1<<k;
			}
		}
		printf("%d\n",now^b);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值