[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 ;
}
posted @ 2019-04-02 06:49  beretty  阅读(140)  评论(0编辑  收藏  举报