Written with StackEdit.
Description
一家餐厅有 (n) 道菜,编号 (1...n) ,大家对第 (i) 道菜的评价值为 (a_i(1≤i≤n))。
有 (m) 位顾客,第 (i) 位顾客的期望值为 (b_i),而他的偏好值为 (x_i) 。因此,第 (i) 位顾客认为第 (j) 道菜的美味度为 (b_i) XOR ((a_j+x_i)),XOR 表示异或运算。
第 (i) 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第(l_i) 道到第 (r_i) 道中选择。请你帮助他们找出最美味的菜。
Input
第(1)行,两个整数,(n),(m),表示菜品数和顾客数。
第(2)行,(n)个整数,(a_1,a_2,...,a_n),表示每道菜的评价值。
第(3)至(m+2)行,每行(4)个整数,(b,x,l,r),表示该位顾客的期望值,偏好值,和可以选择菜品区间。
Output
输出 (m) 行,每行 (1) 个整数,(y_{max}) ,表示该位顾客选择的最美味的菜的美味值。
Sample Input
4 4
1 2 3 4
1 4 1 4
2 3 2 3
3 2 3 3
4 1 2 4
Sample Output
9
7
6
7
HINT
(1≤n≤2×10^5,0≤a_i,b_i,x_i<10^5,1≤l_i≤r_i≤n(1≤i≤m);1≤m≤10^5.)
Solution
- 最大异或值的题目大多采用贪心,各位之间互不影响,从高到低逐位考虑.
- 从高到低考虑(b)的第(j)位,我们肯定是想在(a_i)中找加上(x)后,第(j)位上与(b)相反的数.
- 手算一下可以发现,一个数满足上述条件,若前面的位数已经得到的结果为(ans),那么当且仅当这个数在区间([ans-x,ans+(1<<j)-1-x])内.
- 如果有这样的数,那么这一位的贡献为((b>>j)) xor (1),否则为(b>>j).
- 这样就转化成了在一个区间内询问是否有大小恰好在一个范围内的数,用主席树解决即可.
(3.8 upd:) 重新写了一份代码.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int MAXN=2e5+10,MAXV=1e5+10;
const int lim=17;
int rt[MAXN];
struct PresegTree
{
int idx;
PresegTree(){idx=0;}
struct node{
int ls,rs;
int cnt;
}Tree[MAXV*lim*8];
#define root Tree[o]
#define lson Tree[root.ls]
#define rson Tree[root.rs]
int BuildTree(int l,int r)
{
int o=++idx;
root.cnt=root.ls=root.rs=0;
if(l!=r)
{
int mid=(l+r)>>1;
root.ls=BuildTree(l,mid);
root.rs=BuildTree(mid+1,r);
}
return o;
}
void update(int &o,int pre,int pos,int l,int r)
{
o=++idx;
root=Tree[pre];
++root.cnt;
if(l==r)
return;
int mid=(l+r)>>1;
if(pos<=mid)
update(root.ls,Tree[pre].ls,pos,l,mid);
else
update(root.rs,Tree[pre].rs,pos,mid+1,r);
}
int query(int o,int l,int r,int L,int R)
{
if(l>R || L>r)
return 0;
if(L<=l && r<=R)
return root.cnt;
int mid=(l+r)>>1;
int s=0;
if(L<=mid)
s+=query(root.ls,l,mid,L,R);
if(R>mid)
s+=query(root.rs,mid+1,r,L,R);
return s;
}
}T;
int n,m,a[MAXN],mx=0;
void init()
{
for(int i=1;i<=n;++i)
mx=max(mx,a[i]=read());
rt[0]=T.BuildTree(1,mx);
for(int i=1;i<=n;++i)
T.update(rt[i],rt[i-1],a[i],1,mx);
}
int solve(int b,int x,int L,int R)
{
int selected=0,ans=0;
for(int k=lim;k>=0;--k)
{
int aim=selected;
int p=(b>>k)&1,q=p^1;
aim|=(q<<k);
int l=aim-x,r=aim+(1<<k)-1-x;
l=max(l,1),r=min(r,mx);
int s=T.query(rt[R],1,mx,l,r)-T.query(rt[L-1],1,mx,l,r);
if(s)
{
selected|=(q<<k);
ans+=1<<k;
}
else
{
selected|=(p<<k);
}
}
return ans;
}
int main()
{
// cerr<<sizeof(T)/1024/1024<<endl;
freopen("food.in","r",stdin);
freopen("food.out","w",stdout);
n=read(),m=read();
init();
while(m--)
{
int b=read(),x=read(),L=read(),R=read();
printf("%d
",solve(b,x,L,R));
}
return 0;
}