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