[BZOJ4571][SCOI2016]美味

题目戳这

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,\)表示该位顾客的期望值,偏好值,和可以选择菜品区间。
$ 1≤n≤2×105,0≤a_i,b_i,x_i<105,1≤l_i≤r_i≤n(1≤i≤m);1≤m≤10^5$

Output

输出\(m\)行,每行 1 个整数,\(ymax\),表示该位顾客选择的最美味的菜的美味值。

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

题解

首先在区间\([l,r]\)里面选就肯定是主席树了吧。
然后既然求异或结果最大那么就考虑按位贪心。
\(ans=a_j+x_i\),那么我们就希望\(ans\)在二进制上从高位到低位尽量都与\(b_i\)不同。我们假设不同,那么就是确定了某一个最高位的数值。假设确定的是第\(i\)位的数值,那么我们相当于确定了解的范围,即一个长度为\(2^i\)的区间。接下来就是通过两棵主席树作差找这个范围内是否存在解了。

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N  = 200005;
struct president_tree{int ls,rs,num;}t[N*25];
int n,m,a,rt[N],tot,b,x,l,r,L,R,ans,opt;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
void build(int &now,int l,int r)
{
	now=++tot;
	if (l==r) return;
	int mid=l+r>>1;
	build(t[now].ls,l,mid);
	build(t[now].rs,mid+1,r);
}
void update(int &now,int l,int r,int pos)
{
	t[++tot]=t[now];
	t[now=tot].num++;
	if (l==r) return;
	int mid=l+r>>1;
	if (pos<=mid) update(t[now].ls,l,mid,pos);
	else update(t[now].rs,mid+1,r,pos);
}
int Query(int A,int B,int l,int r,int ql,int qr)
{
	if (l>=ql&&r<=qr) return t[A].num-t[B].num;
	int mid=l+r>>1,s=0;
	if (ql<=mid) s+=Query(t[A].ls,t[B].ls,l,mid,ql,qr);
	if (qr>mid) s+=Query(t[A].rs,t[B].rs,mid+1,r,ql,qr);
	return s;
}
int main()
{
	n=gi();m=gi();
	build(rt[0],1,N);
	for (int i=1;i<=n;i++)
	{
		a=gi();
		rt[i]=rt[i-1];
		update(rt[i],0,N,a);
	}
	while (m--)
	{
		b=gi();x=gi();l=gi();r=gi();ans=0;
		for (int i=17;i>=0;i--)
		{
			if (b&(1<<i)) L=ans,R=ans+(1<<i)-1,opt=0;
			else L=ans+(1<<i),R=ans+(1<<i+1)-1,opt=1;
			if (!Query(rt[r],rt[l-1],0,N,max(0,L-x),min(N,R-x))) opt^=1;
			ans|=opt<<i;
		}
		printf("%d\n",ans^b);
	}
	return 0;
}

posted @ 2017-12-28 22:23  租酥雨  阅读(503)  评论(0编辑  收藏  举报