洛谷传送门
BZOJ传送门
LOJ传送门
解析:
如果你像我一样对01Trie非常熟悉,那么你开头一定想的是可持久化01Trie。然而我们发现这个加法把一切都打乱了。。。
于是这道题的 O ( log n ) O(\log n) O(logn)回答每个询问的做法是不存在的。
我们按位贪心,考虑令当前位和 b b b的当前位不同,那么我们的 r e s res res是有一个取值范围的,将这个取值范围整体减少 x x x之后询问 l , r l,r l,r范围中是否存在加上 x x x能够得到 r e s res res的值,显然这个可以用主席树随便做。
单次询问 O ( log 2 ) O(\log^2) O(log2)
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
using std::cout;
using std::cerr;
using std::swap;
cs int N=2e5+5;
cs int SIZE=N*30;
int n,m;
int rt[N];
int son[SIZE][2],siz[SIZE];
int tot;
cs int maxn=1e5;
inline void insert(cs int &pre,int &now,cs int &l,cs int &r,cs int &val){
now=++tot;
son[now][0]=son[pre][0];
son[now][1]=son[pre][1];
siz[now]=siz[pre]+1;
if(l==r)return ;
int mid=(l+r)>>1;
if(val<=mid)insert(son[pre][0],son[now][0],l,mid,val);
else insert(son[pre][1],son[now][1],mid+1,r,val);
}
inline bool query(cs int <,cs int &rt,cs int &l,cs int &r,cs int &ql,cs int &qr){
if(siz[rt]==siz[lt])return false;
if(ql<=l&&r<=qr)return true;
int mid=(l+r)>>1;
if(qr<=mid)return query(son[lt][0],son[rt][0],l,mid,ql,qr);
if(mid<ql)return query(son[lt][1],son[rt][1],mid+1,r,ql,qr);
return query(son[lt][0],son[rt][0],l,mid,ql,qr)||query(son[lt][1],son[rt][1],mid+1,r,ql,qr);
}
signed main(){
n=getint(),m=getint();
for(int re i=1;i<=n;++i)insert(rt[i-1],rt[i],0,maxn,getint());
while(m--){
int b=getint(),x=getint(),l=rt[getint()-1],r=rt[getint()];
int res=0;
for(int re i=17,now;~i;--i){
now=res|((((b>>i)&1)^1)<<i);
if(query(l,r,0,maxn,now-x,now+(1<<i)-1-x))res=now;
else res|=((b>>i)&1)<<i;
}
cout<<(res^b)<<"\n";
}
return 0;
}