4571: [Scoi2016]美味
Time Limit: 30 Sec
Memory Limit: 256 MB
Submit: 704
Solved: 380
[ Submit][ Status][ Discuss]
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
对于一般的区间异或最大,就直接可持久化trie,但是该题有加法(a[j]+x[i]),便不能用可持久化trie,可以用可持久化线段树。
一个满的可持久化线段树可以看做左儿子为0,右儿子为1,希望异或和最大,则b[i]的第k位为0,那么去找第k位是否有1的,没有的话就选0(反之亦然)。从二进制的最高位开始找,便可找到最大值。
此处重点是怎么处理(a[j]+x[i]),我们把a[j]全部加入可持久化线段树里,对于第i个询问:
假设现在是做第一次操作,对第k位进行查询,b[i]的第k位为0,// k从0开始
则我们要找是否存在一个(a[j]+x[i]) 的第k位为1,
即找是否存在 1<
即找是否存在 1<
这样我们便可以在主席树上查找了。每次操作以后统计入答案里。
可参考代码(int main 里的)理解
#include
#include
#define N 200005
#define M 8000005
#define INF 1<<20
using namespace std;
int rt[N],tr[M],n,m,b,x,l,r,a[N],son[M][2],sz,ans;
void insert(int &p1,int &p2,int l,int r,int x){
if(xr) return ;
if(!p1) p1=++sz;
if(!p2) p2=++sz;
tr[p1]=tr[p2];
tr[p1]++;
if(l==x&&r==x) return ;
int mid=(l+r)/2;
if(l<=x&&x<=mid){son[p1][1]=son[p2][1];insert(son[p1][0],son[p2][0],l,mid,x);}
else{son[p1][0]=son[p2][0];insert(son[p1][1],son[p2][1],mid+1,r,x);}
}
bool find(int p1,int p2,int l,int r,int x,int y){
if(y=0;j--){
if(b&(1<