[SCOI2016]美味
链接:https://www.luogu.org/problemnew/show/3293
题意:
一家餐厅有 n 道菜,编号 1...n ,大家对第 i 道菜的评价值为 ai(1<=i<=n)。有 m 位顾客,第 i 位顾客的期望值为 bi,而他的偏好值为 xi 。因此,第 i 位顾客认为第 j 道菜的美味度为 bi XOR (aj+xi),XOR 表示异或运算。
第 i 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 li 道到第 ri 道中选择。请你帮助他们找出最美味的菜。
数据范围:n,m,a[i]<=10e5
题解:
很水的一道题啊。。。
考虑xor运算,每一位都是互相独立的,所以若要总的值越大,即越靠前的位越大
从前向后考虑每一位,若该位要取1才能得到最大值
则(aj+xi)的范围应该sum--------sum+(1<<i)-1 {这步最关键}
则只需查找aj属于sum-a[j]-------sum+(1<<i)-1-a[j]即可
之后就显然了。。主席树维护
****注意优先级要多打括号啊。。。
代码:
#include <bits/stdc++.h>
#define mid (h+t)/2
#define maxn 100000
using namespace std;
struct re{int h,t,x;}p[10000000];
int n,m,j,now,a[300000],fa[300000],f[100];
void build(int x,int h,int t)
{
now=max(now,x);
if (h==t) return;
p[x].h=x*2; p[x].t=x*2+1;
build(x*2,h,mid); build(x*2+1,mid+1,t);
};
void insert(int x,int &y,int num,int h,int t)
{
y=++now,p[y]=p[x]; p[y].x++;
if (h==t) return;
if (mid>=num) insert(p[x].h,p[y].h,num,h,mid);
else insert(p[x].t,p[y].t,num,mid+1,t);
};
bool query(int x,int y,int h1,int t1,int h,int t)
{
if (t<h1 || t1<h) return(false);
if (h1<=h && t<=t1) return((p[y].x-p[x].x)>0);
return(query(p[x].h,p[y].h,h1,t1,h,mid) || query(p[x].t,p[y].t,h1,t1,mid+1,t));
}
int main(){
freopen("noip.in","r",stdin);
freopen("noip.out","w",stdout);
cin>>n>>m;
build(1,1,n);
fa[0]=1;
for (int i=1;i<=n;i++)
cin>>a[i],insert(fa[i-1],fa[i],a[i],0,maxn);
for (j=1;f[j-1]<=100000;j++) f[j]=1<<(j-1);
int tmp=j-1;
for (int i=1;i<=m;i++)
{
int c1,d1,x,y,ll=0;
cin>>c1>>d1>>x>>y;
for (int j=tmp;j>0;j--)
{
if ((f[j]&c1)>0)
{
if (!query(fa[x-1],fa[y],max(0,ll-d1),ll+f[j]-1-d1,0,maxn))
ll+=f[j];
}
else
if (query(fa[x-1],fa[y],max(0,ll+f[j]-d1),ll+2*f[j]-1-d1,0,maxn))
ll+=f[j];
}
cout<<(c1^ll)<<endl;
}
}