题目描述
一家餐厅有 $n$ 道菜,编号 $1 ldots n$,大家对第 $i$ 道菜的评价值为 $a_i :( 1 leq i leq n ) :$。有 $m$ 位顾客,第 $i$ 位顾客的期望值为 $b_i$,而他的偏好值为 $x_i$。因此,第 $i$ 位顾客认为第 $j$ 道菜的美味度为 $b_i mathbin{ ext{xor}} (a_j + x_i)$($ ext{xor}$ 表示异或运算)。
第 $i$ 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 $l_i$ 道到第 $r_i$ 道中选择。请你帮助他们找出最美味的菜。
数据范围
$1 leq n leq 2 imes 10 ^ 5, 0 leq a_i, b_i, x_i < 10 ^ 5, 1 leq l_i leq r_i leq n(1 leq i leq m), 1 leq m leq 10 ^ 5$
题解
考虑拆位
考虑从高到低做到第 $i$ 位,判断第 $i$ 位上的 $a_i+x$ 的值是多少
假设前几位得到的答案是 $s$ ,如果 $b$ 第 $i$ 位上是 $1$ 的话,那希望 $s$ 在第 $i$ 位上是 $0$,所以希望有 $a_i+x∈[s,s+2^i-1]$ ,所以 $a_i ∈ [s-x,s+2^i-1-x]$ ,反之是类似的
然后判断[l,r]中有没有出现这类数,用主席树维护即可
效率:$O(n logn loga_i)$
代码
#include <bits/stdc++.h> using namespace std; const int N=2e5+5,M=1e5,Z=N*20; int n,m,T[N],ls[Z],rs[Z],s[Z],t; #define mid ((l+r)>>1) void insert(int &x,int y,int l,int r,int v){ x=++t;s[x]=s[y]+1; if (l==r) return;ls[x]=ls[y];rs[x]=rs[y]; if (mid>=v) insert(ls[x],ls[y],l,mid,v); else insert(rs[x],rs[y],mid+1,r,v); } int query(int x,int y,int l,int r,int L,int R){ if (L>R) return 0; if (L==l && r==R) return s[y]-s[x]; if (mid>=R) return query(ls[x],ls[y],l,mid,L,R); if (mid<L) return query(rs[x],rs[y],mid+1,r,L,R); return query(ls[x],ls[y],l,mid,L,mid)+query(rs[x],rs[y],mid+1,r,mid+1,R); } int main(){ scanf("%d%d",&n,&m); for (int x,i=1;i<=n;i++) scanf("%d",&x),insert(T[i],T[i-1],0,M,x); for (int b,x,l,r,s;m--;){ scanf("%d%d%d%d",&b,&x,&l,&r);s=0; for (int L,R,j=17;~j;j--){ if (b&(1<<j)) L=s,R=s+(1<<j)-1; else L=s+(1<<j),R=s+(1<<(j+1))-1;s|=(b&(1<<j)); if (query(T[l-1],T[r],0,M,max(L-x,0),min(R-x,M))) s^=(1<<j); } printf("%d ",s^b); } return 0; }