#2656. 美味(food)

题目描述
一家餐厅有 $n$ 道菜,编号 $1 \ldots n$,大家对第 $i$ 道菜的评价值为 $a_i \:( 1 \leq i \leq n ) \:$。有 $m$ 位顾客,第 $i$ 位顾客的期望值为 $b_i$,而他的偏好值为 $x_i$。因此,第 $i$ 位顾客认为第 $j$ 道菜的美味度为 $b_i \mathbin{\text{xor}} (a_j + x_i)$($\text{xor}$ 表示异或运算)。

第 $i$ 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 $l_i$ 道到第 $r_i$ 道中选择。请你帮助他们找出最美味的菜。

数据范围
$1 \leq n \leq 2 \times 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\n",s^b);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xjqxjq/p/11309175.html