Solution
emmm持续智力康复。。
虽然说因为统计的是加上(x)的跟(b)异或的最大值所以可持久化trie用不了了
但是按位贪心的思想还是非常ok的
然后又因为权值范围比较小,那就权值线段树然后可持久化一下,对于一个查询(b),我们从高位到低位枚举每一位,对于当前枚举到的第(j)位,先确定一个范围,这个范围内的任意一个数(i)加上(x)后都满足(i)^(b)的结果的第(j)位为1,然后我们在这个范围内的主席树上查一下有没有在这个区间内的数,有的话就说明这位可以满足异或后为(1),搞到答案里面去,否则就不能为(1),不管,然后接着枚举下一位,总的复杂度(O(nlog^2n))
(其实就是。。把按位贪心的过程从trie上面搬到了主席树上。。)
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=2*(1e5)+10,SEG=N*20,MX=N,TOP=20;
int a[N];
int n,m,mx,L,R;
namespace Seg{/*{{{*/
int ch[SEG][2],sum[SEG],rt[N];
int n,tot;
void init(int _n){n=_n; tot=0;}
int newnode(int pre){
ch[++tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1]; sum[tot]=sum[pre];
return tot;
}
void _insert(int pre,int &x,int d,int lx,int rx){
x=newnode(pre);
++sum[x];
if (lx==rx) return;
int mid=lx+rx>>1;
if (d<=mid) _insert(ch[pre][0],ch[x][0],d,lx,mid);
else _insert(ch[pre][1],ch[x][1],d,mid+1,rx);
}
void insert(int pre,int x,int d){_insert(rt[pre],rt[x],d,1,n);}
bool _query(int L,int R,int l,int r,int lx,int rx){
if (!R) return 0;
if (l<=lx&&rx<=r) return (sum[R]-sum[L])>0;
int mid=lx+rx>>1,ret=0;
if (l<=mid) ret|=_query(ch[L][0],ch[R][0],l,r,lx,mid);
if (r>mid) ret|=_query(ch[L][1],ch[R][1],l,r,mid+1,rx);
return ret;
}
bool query(int tL,int tR,int l,int r){return _query(rt[tL-1],rt[tR],l,r,1,n);}
}/*}}}*/
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int b,x,l,r,tmp;
scanf("%d%d",&n,&m);
Seg::init(MX);
for (int i=1;i<=n;++i){
scanf("%d",a+i);
Seg::insert(i-1,i,a[i]);
}
for (int i=1;i<=m;++i){
scanf("%d%d%d%d",&b,&x,&l,&r);
tmp=0;
for (int j=TOP;j>=0;--j){
if (b>>j&1){
L=max(0,tmp-x); R=(tmp|((1<<j)-1))-x;
if (R<0||!Seg::query(l,r,L,R)) tmp^=(1<<j);
}
else{
L=max(0,(tmp^(1<<j))-x); R=((tmp^(1<<j))|((1<<j)-1))-x;
if (R<0||!Seg::query(l,r,L,R)) continue;
else tmp^=(1<<j);
}
}
printf("%d
",tmp^b);
}
}