BZOJ4571:[SCOI2016]美味(主席树,贪心)

按位贪心算法解决顾客美食选择问题

Description

一家餐厅有 n 道菜,编号 1...n ,大家对第 i 道菜的评价值为 ai(1≤i≤n)。有 m 位顾客,第 i 位顾客的期望值为 bi,而他的偏好值为 xi 。
因此,第 i 位顾客认为第 j 道菜的美味度为 bi XOR (aj+xi),XOR 表示异或运算。
第 i 位顾客希望从这些菜中挑出他认为最美味的菜,即美味值最大的菜,但由于价格等因素,他只能从第 li 道到第 ri 道中选择。
请你帮助他们找出最美味的菜。

Input

第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

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

Solution

感觉自己有点傻……

考虑按位贪心。

首先要明确一个东西,我们最终要输出的是$ans~xor~b$,所以贪$ans$的时候要注意一下。

若$b$的第$i$位为$1$,那么如果在区间$[ans-x,(ans|((1<<i)-1))-x]$如果没有数的话,$ans$的第$i$位就置为$1$,也就是对应着答案这里这一位选不上,成$0$了。

若$b$的第$i$位为$0$的情况同理……我也说不太清楚……看看代码感性理解一下吧……QAQ

Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #define N (200009)
 4 using namespace std;
 5 
 6 struct Sgt{int ls,rs,val;}Segt[N<<5];
 7 int n,m,b,x,l,r,L,R,ans,sgt_num,a[N],Root[N];
 8 
 9 int Update(int pre,int l,int r,int x)
10 {
11     int now=++sgt_num;
12     Segt[now]=Segt[pre]; Segt[now].val++;
13     if (l==r) return now;
14     int mid=(l+r)>>1;
15     if (x<=mid) Segt[now].ls=Update(Segt[now].ls,l,mid,x);
16     else Segt[now].rs=Update(Segt[now].rs,mid+1,r,x);
17     return now;
18 }
19 
20 int Query(int u,int v,int l,int r,int l1,int r1)
21 {
22     if (l>r1 || r<l1) return 0;
23     if (l1<=l && r<=r1) return Segt[v].val-Segt[u].val;
24     int mid=(l+r)>>1;
25     return Query(Segt[u].ls,Segt[v].ls,l,mid,l1,r1)+Query(Segt[u].rs,Segt[v].rs,mid+1,r,l1,r1);
26 }
27 
28 int main()
29 {
30     scanf("%d%d",&n,&m);
31     for (int i=1; i<=n; ++i)
32         scanf("%d",&a[i]), Root[i]=Update(Root[i-1],0,1e5,a[i]);
33     while (m--)
34     {
35         ans=0;
36         scanf("%d%d%d%d",&b,&x,&l,&r);
37         for (int i=17; i>=0; --i)
38             if (b&(1<<i))
39             {
40                 L=max(0,ans-x); R=(ans|((1<<i)-1))-x;
41                 if (!Query(Root[l-1],Root[r],0,1e5,L,R)) ans|=(1<<i);
42             }
43             else
44             {
45                 ans|=(1<<i);
46                 L=max(0,ans-x); R=(ans|((1<<i)-1))-x;
47                 if (!Query(Root[l-1],Root[r],0,1e5,L,R)) ans^=(1<<i);
48             }
49         printf("%d\n",ans^b);
50     }
51 }

转载于:https://www.cnblogs.com/refun/p/10087564.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值