[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
用主席树维护1~r内节点代表区间的值有多少个
我们求出使b^ans最大的ans
首先考虑贪心,即匹配到了第i位,那么第i+1位能要就要
从一位i开始,b这一位假设是1
那么看l~r之间有无使b第i位为1的,因为贪心,所以我们尽可能使i位为1就行,前i-1位可以不管
显然我们已经处理了前i-1位了,设当前结果是ans
所以我们要查询的范围为[ans-x,ans+(1<<i)-1-x]
查询范围+ans是为了贪心满足前面的位的情况下才算

右端的意思是后面的位由于贪心不管
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int pos,root[200001],ch[5000001][2],sum[5000001],n,m,a[200001];
 7 void update(int &rt,int l,int r,int x)
 8 {
 9   int Rt=rt;
10   rt=++pos;
11   ch[rt][0]=ch[Rt][0];ch[rt][1]=ch[Rt][1];
12   sum[rt]=sum[Rt]+1;
13   if (l==r) return;
14   int mid=(l+r)/2;
15   if (x<=mid) update(ch[rt][0],l,mid,x);
16   else update(ch[rt][1],mid+1,r,x);
17 }
18 int query(int rt1,int rt2,int l,int r,int L,int R)
19 {
20   if (l>=L&&r<=R)
21     return sum[rt2]-sum[rt1];
22   int mid=(l+r)/2,s=0;
23   if (L<=mid) s+=query(ch[rt1][0],ch[rt2][0],l,mid,L,R);
24   if (R>mid) s+=query(ch[rt1][1],ch[rt2][1],mid+1,r,L,R);
25   return s;
26 }
27 bool find(int i,int j,int l,int r)
28 {
29   if (l<0) l=0;
30   if (r>100000) r=100000;
31   if (l>r) return 0;
32   if (query(root[i],root[j],0,100000,l,r)) return 1;
33   return 0;
34 }
35 int main()
36 {int i,b,x,l,r,j;
37   cin>>n>>m;
38   for (i=1;i<=n;i++)
39     {
40       scanf("%d",&a[i]);
41       root[i]=root[i-1];
42       update(root[i],0,100000,a[i]);
43     }
44   for (i=1;i<=m;i++)
45     {
46       scanf("%d%d%d%d",&b,&x,&l,&r);
47       int ans=0;
48       for (j=17;j>=0;j--)
49     {
50       int now=ans+((1^((b>>j)&1))<<j);
51       if (find(l-1,r,now-x,now+(1<<j)-1-x)) ans=now;
52       else ans+=(((b>>j)&1)<<j);
53     }
54       printf("%d\n",ans^b);
55     }
56 }

 

posted @ 2018-01-08 08:12  Z-Y-Y-S  阅读(260)  评论(0编辑  收藏  举报