题目描述
一家餐厅有 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 ,表示该位顾客选择的最美味的菜的美味值。
输入输出样例
4 4 1 2 3 4 1 4 1 4 2 3 2 3 3 2 3 3 4 1 2 4
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 }