[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,表示该位顾客的期望值,偏好值,和可以选择菜品区间。1<=n<=2*10^5,0<=ai,bi,xi<10^5,1<=li<=ri<=n(1<=i<=m);1<=m<=10^5

输出格式:

输出 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

题解:

 一开始看到这题,觉得不可做。

一看标签,主席树?Impossible!

于是乎,点开题解堕落。

既然题目问的是异或值最大,我们不妨来一个贪心,从高位到低位。

首先按照输入的顺序建立权值主席树。然后将输入的数的位数从高到低的顺序贪心,如果当前区间内有可以让这一位经过异或运算后为1的数,那么就将范围缩小。

 1 //Never forget why you start
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<cmath>
 7 #include<algorithm>
 8 #define ll(x) seg[x].l
 9 #define rr(x) seg[x].r
10 using namespace std;
11 int n,m,ans,a[200005];
12 int root[200005],cnt;
13 struct seg{
14   int l,r,cnt;
15 }seg[10000005];
16 int newnode(int root){
17   cnt++;
18   seg[cnt].l=seg[root].l;
19   seg[cnt].r=seg[root].r;
20   seg[cnt].cnt=seg[root].cnt;
21   return cnt;
22 }
23 void push_up(int root){
24   seg[root].cnt=seg[ll(root)].cnt+seg[rr(root)].cnt;
25 }
26 void insert(int &root,int l,int r,int x){
27   root=newnode(root);
28   if(l==r){seg[root].cnt++;return;}
29   int mid=(l+r)>>1;
30   if(x<=mid)insert(ll(root),l,mid,x);
31   if(mid<x)insert(rr(root),mid+1,r,x);
32   push_up(root);
33 }
34 int query(int lroot,int rroot,int left,int right,int l,int r){
35   if(l<=left&&right<=r)return seg[rroot].cnt-seg[lroot].cnt;
36   if(l>right||r<left)return 0;
37   int mid=(left+right)>>1,ans=0;
38   if(l<=mid)ans+=query(ll(lroot),ll(rroot),left,mid,l,r);
39   if(mid<r)ans+=query(rr(lroot),rr(rroot),mid+1,right,l,r);
40   return ans;
41 }
42 int main(){
43   int i,j;
44   scanf("%d%d",&n,&m);
45   for(i=1;i<=n;i++){
46     scanf("%d",&a[i]);
47     root[i]=root[i-1];
48     insert(root[i],1,1e5,a[i]);
49   }
50   for(i=1;i<=m;i++){
51     int b,x,l,r;
52     ans=0;
53     scanf("%d%d%d%d",&b,&x,&l,&r);
54     for(j=17;j>=0;j--){
55       int now=ans+((1^((b>>j)&1))<<j);
56       if(query(root[l-1],root[r],1,1e5,now-x,now+(1<<j)-1-x))ans=now;
57       else ans+=((b>>j)&1)<<j;
58     }
59     printf("%d\n",ans^b);
60   }
61   return 0;
62 }

 

posted @ 2018-01-10 10:50  kakakakakaka  阅读(177)  评论(0编辑  收藏  举报

Never forget why you start

//鼠标爆炸特效