【BZOJ4571】美味(主席树)

时间:2021-09-21 03:38:30

【BZOJ4571】美味(主席树)

题面

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×105,0≤ai,bi,xi<105,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

题解

真题真的好诶。。。

如果是一个啥东西\(xor\ ai\)应该还是很好做的

直接搭一个可持久化Trie树就行了

但是,现在是\(b\ xor \ ai\)

我们按照位来考虑,

如果当前是第\(l\)位

那么,如果能够贪心的匹配上一个1的话

显然,那就在一个范围内需要存在\(ai\)的值

因此,对于\(ai\)搭值域线段树

每次查询区间内是否存在\(ai\)的值

如果存在,本次贪心有效

否则无效

最后就很简单了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 500000
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Node
{
int ls,rs;
int v;
}t[MAX<<5];
int tot,rt[MAX],N=200005;
int B,X,L,R;
int n,m,a[MAX];
void Build(int &now,int l,int r)
{
now=++tot;
if(l==r)return;
int mid=(l+r)>>1;
Build(t[now].ls,l,mid);
Build(t[now].rs,mid+1,r);
}
void Modify(int &now,int ff,int l,int r,int pos)
{
now=++tot;t[now]=t[ff];t[now].v++;
if(l==r)return;
int mid=(l+r)>>1;
if(pos<=mid)Modify(t[now].ls,t[ff].ls,l,mid,pos);
else Modify(t[now].rs,t[ff].rs,mid+1,r,pos);
}
int Query(int A,int B,int l,int r,int al,int ar)
{
if(al<=l&&r<=ar)return t[A].v-t[B].v;
int mid=(l+r)>>1,ret=0;
if(al<=mid)ret+=Query(t[A].ls,t[B].ls,l,mid,al,ar);
if(ar>mid)ret+=Query(t[A].rs,t[B].rs,mid+1,r,al,ar);
return ret;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)a[i]=read();
Build(rt[0],0,N);
for(int i=1;i<=n;++i)Modify(rt[i],rt[i-1],0,N,a[i]);
while(m--)
{
B=read();X=read();L=read();R=read();
int ans=0;
int ll,rr;
for(int i=17,g;i>=0;--i)
{
if(B&(1<<i))ll=ans,rr=ans+(1<<i)-1,g=0;
else ll=ans+(1<<i),rr=ans+(1<<(i+1))-1,g=1;
if(!Query(rt[R],rt[L-1],0,N,max(0,ll-X),min(N,rr-X)))g^=1;
ans+=g<<i;
}
printf("%d\n",ans^B);
}
}