[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;
  }
}

 

posted @ 2017-12-11 23:13  尹吴潇  阅读(309)  评论(0编辑  收藏  举报