题目描述:
给出 N 个 A
给出 Q 个 询问
每个询问有四个量 分别为 B,X,L,R
每个A 的价值为
B xor (X+Ai)(l<=i<=r)
B
x
o
r
(
X
+
A
i
)
(
l
<=
i
<=
r
)
求出最大的价值
题目分析:
如果没有那个 X 的 干扰 ,那我们就可以用可持久化Tire树搞一下
同样是按照数位一位一位的贪心,因为加了一个x,所以我们考虑对于所有的ai+x与b的按位异或。
假设我们已经处理到b的第i位(转换成二进制),假设是1(0同理),
那么我们只需要查找是否存在aj+x使得其二进制第i位数字是0,显然我们已经处理了前i-1位了,设当前结果是ans,那么我们需要查找的数的大小就是在区间 [ans−x,ans+(1<<i)−1−x] [ a n s − x , a n s + ( 1 << i ) − 1 − x ] ,手算一下就知道这个区间里的数字的第i位加了x后就都是0,
那么现在我们就是要在a[1]…a[n]中找出是否存在于 [ans−x,ans+(1<<i)−1−x] [ a n s − x , a n s + ( 1 << i ) − 1 − x ] 的数字,两个区间范围限制,用主席树模板一套就好了。
由于多了个查询范围,比朴素的主席树维护的方法多了个log 不过还是受得起的
题目链接:
AC 代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
const int maxm=4000005;
const int N=2*1e5+100;
int lson[maxm],rson[maxm],sum[maxm];
int rt[N],siz,n,q,maxr;
void insert(int &o,int pre,int l,int r,int ind)
{
o=++siz;
lson[o]=lson[pre],rson[o]=rson[pre],sum[o]=sum[pre]+1;
if(l==r) return;
int mid=(l+r)>>1;
if(ind<=mid) insert(lson[o],lson[pre],l,mid,ind);
else insert(rson[o],rson[pre],mid+1,r,ind);
}
int asksum(int o,int pre,int l,int r,int ql,int qr)
{
//printf("%d %d\n",l,r);
if(ql<=l&&r<=qr) return sum[o]-sum[pre];
int mid=(l+r)>>1;
int sumx=0;
if(ql<=mid) sumx+=asksum(lson[o],lson[pre],l,mid,ql,qr);
if(qr>mid) sumx+=asksum(rson[o],rson[pre],mid+1,r,ql,qr);
return sumx;
}
int main()
{
maxr=262144;
scanf("%d%d",&n,&q);
for(int i=1,x;i<=n;i++) scanf("%d",&x),insert(rt[i],rt[i-1],0,maxr,x);
while(q--)
{
int l,r,x,b;
int ans=0;
scanf("%d%d%d%d",&b,&x,&l,&r);
l--;
for(int i=17;i>=0;i--)
{
if(!((b>>i)&1)) ans^=(1<<i);
int ql=std::max(ans-x,0),qr=ans+(1<<i)-x-1;
if(qr<0||!asksum(rt[r],rt[l],0,maxr,ql,qr)) ans^=(1<<i);
}
printf("%d\n",ans^b);
}
return 0;
}