测试地址:美味
做法:本题需要用到主席树+贪心。
考虑一次询问,要使
bi xor (aj+xi)
b
i
x
o
r
(
a
j
+
x
i
)
最大,我们从高位向低位贪心,我们知道涉及的询问是:将每个数按二进制位从高位到低位写出,对于某一个前缀,询问存不存在异或
bi
b
i
后满足前缀为当前前缀的
aj+xi
a
j
+
x
i
。我们发现满足要求的
aj
a
j
是一个区间,而看一个区间内有没有数显然可以用权值线段树解决。而题目中又要求了区间,使用主席树即可。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,a[200010],maxa,rt[200010];
int tot=0,seg[4000010],ch[4000010][2];
void buildtree(int &v,int l,int r)
{
v=++tot;
seg[v]=ch[v][0]=ch[v][1]=0;
if (l==r) return;
int mid=(l+r)>>1;
buildtree(ch[v][0],l,mid);
buildtree(ch[v][1],mid+1,r);
}
void insert(int &v,int last,int l,int r,int x)
{
v=++tot;
seg[v]=seg[last];
ch[v][0]=ch[last][0];
ch[v][1]=ch[last][1];
if (l==r) {seg[v]++;return;}
int mid=(l+r)>>1;
if (x<=mid) insert(ch[v][0],ch[last][0],l,mid,x);
else insert(ch[v][1],ch[last][1],mid+1,r,x);
seg[v]=seg[ch[v][0]]+seg[ch[v][1]];
}
int query(int v,int last,int l,int r,int s,int t)
{
if (t<0||s>maxa) return 0;
if (l>=s&&r<=t) return seg[v]-seg[last];
int sum=0,mid=(l+r)>>1;
if (s<=mid) sum+=query(ch[v][0],ch[last][0],l,mid,s,t);
if (t>mid) sum+=query(ch[v][1],ch[last][1],mid+1,r,s,t);
return sum;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
maxa=max(maxa,a[i]);
}
buildtree(rt[0],0,maxa);
for(int i=1;i<=n;i++)
insert(rt[i],rt[i-1],0,maxa,a[i]);
for(int i=1;i<=m;i++)
{
int b,x,l,r;
scanf("%d%d%d%d",&b,&x,&l,&r);
int nowl=0,nowr=(1<<20)-1;
for(int j=19;j>=0;j--)
{
if (b&(1<<j))
{
if (query(rt[r],rt[l-1],0,maxa,nowl-x,nowr-(1<<j)-x)) nowr=nowr-(1<<j);
else nowl=nowl+(1<<j);
}
else
{
if (query(rt[r],rt[l-1],0,maxa,nowl+(1<<j)-x,nowr-x)) nowl=nowl+(1<<j);
else nowr=nowr-(1<<j);
}
}
printf("%d\n",b^nowl);
}
return 0;
}