[SCOI2016]美味
题目描述
一家餐厅有 n 道菜,编号 1...n ,大家对第 i 道菜的评价值为 ai(1<=i<=n)。有 m 位顾客,第 i 位顾客的期望值为 bi,而他的偏好值为 xi 。因此,第 i 位顾客认为第 j 道菜的美味度为 bi XOR (aj+xi),XOR 表示异或运算。
第 i 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 li 道到第 ri 道中选择。请你帮助他们找出最美味的菜。
输入输出格式
输入格式:
第1行,两个整数,n,m,表示菜品数和顾客数。
第2行,n个整数,a1,a2,...,an,表示每道菜的评价值。
第3至m+2行,每行4个整数,b,x,l,r,表示该位顾客的期望值,偏好值,和可以选择菜品区间。
输出格式:
输出 m 行,每行 1 个整数,ymax ,表示该位顾客选择的最美味的菜的美味值。
输入输出样例
输入样例#1:
4 4
1 2 3 4
1 4 1 4
2 3 2 3
3 2 3 3
4 1 2 4
输出样例#1:
9
7
6
7
题解
先不考虑那个\(+x\)
我们显然要贪心的从高位向低位决策
那么我们已经贪心的处理完了前\(i-1\)位,这时候的答案是\(k\)
假设这一位的\(b\)是\(0\)
那么我们只需要查询\([k+2^i,k+2^i+2^i-1]\)这个值域区间存不存在数即可
然后对于那个\(+x\),就相当于每次查询值的时候减掉\(x\)
也就是说最后对于每一位查询的值域区间是\([k+2^i-x,k+2^i+2^i-1-x]\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
const int M = 200005 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
int n , m , upp = 200000 , tot , val[M] , rt[M] ;
struct Node { int l , r , sum ; } t[M * 20] ;
void Insert(int x , int l , int r , int &now , int pre) {
now = ++ tot ; t[now] = t[pre] ; t[now].sum ++ ;
if(l == r) return ; int mid = (l + r) >> 1 ;
if(mid >= x) Insert(x , l , mid , t[now].l , t[pre].l) ;
else Insert(x , mid + 1 , r , t[now].r , t[pre].r) ;
}
int query(int i , int j , int L , int R , int l , int r) {
if(l >= L && r <= R) return t[j].sum - t[i].sum ; int mid = (l + r) >> 1 ;
if(mid >= R) return query(t[i].l , t[j].l , L , R , l , mid) ;
else if(mid < L) return query(t[i].r , t[j].r , L , R , mid + 1 , r) ;
else return query(t[i].l , t[j].l , L , mid , l , mid) + query(t[i].r , t[j].r , mid + 1 , R , mid + 1 , r) ;
}
int main() {
n = read() ; m = read() ;
for(int i = 1 ; i <= n ; i ++) {
val[i] = read() ;
Insert(val[i] , 0 , upp , rt[i] , rt[i - 1]) ;
}
while(m --) {
int b = read() , x = read() , l = read() , r = read() , ans = 0 ;
for(int i = 18 ; i >= 1 ; i --) {
bool dlt = (b & (1 << (i - 1))) ; dlt ^= 1 ;
if(query( rt[l - 1] , rt[r] , ans + dlt * (1 << (i - 1)) - x , ans + dlt * (1 << (i - 1)) + (1 << (i - 1)) - 1 - x , 0 , upp ))
ans = ans + dlt * (1 << (i - 1)) ;
else ans = ans + (dlt ^ 1) * (1 << (i - 1)) ;
}
printf("%d\n",ans ^ b) ;
}
return 0 ;
}