据说这题做法叫做可持久化trie树?(然而我并不会)
首先考虑一下贪心,从高位到低位枚举,如果能选1肯定比选0优
假设已经处理到了$b$的第$i$位,为1(为0的话同理就不说了)
那么只有当$a_j+x$的第$i$位为0时才能让答案的第$i$位为$1$
考虑把$x$的影响去掉。如果当前的答案是$ans$(即令前面几位贪心情况下最大且第$i$位为0时的$a$),那么只有在区间$[ans-x,ans+(1<<i)-1-x]$的数能在加上$x$之后第$i$位为0(这个可以自己手动算一算)
如果存在,那么$ans$第$i$位变为0(存在前$i$位与之相同且第$i$位为0的$a_i$),否则变为1(只存在前$i$位与之相同且第$i$位为0的$a_i$)
然后查找是两个区间限制主席树套上去就好了
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 using namespace std; 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 6 char buf[1<<21],*p1=buf,*p2=buf; 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 8 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 char sr[1<<21],z[20];int C=-1,Z; 20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 21 inline void print(int x){ 22 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 23 while(z[++Z]=x%10+48,x/=10); 24 while(sr[++C]=z[Z],--Z);sr[++C]=' '; 25 } 26 const int N=2e5+5,M=N*20; 27 int rt[N],L[M],R[M],sum[M],a[N],cnt,n,q,m; 28 void update(int &now,int last,int x,int l=0,int r=m){ 29 sum[now=++cnt]=sum[last]+1; 30 if(l==r) return; 31 int mid=(l+r)>>1; 32 if(x<=mid) R[now]=R[last],update(L[now],L[last],x,l,mid); 33 else L[now]=L[last],update(R[now],R[last],x,mid+1,r); 34 } 35 int query(int u,int v,int ql,int qr,int l=0,int r=m){ 36 if(ql<=l&&qr>=r) return sum[u]-sum[v]; 37 int mid=(l+r)>>1; 38 if(ql<=mid&&query(L[u],L[v],ql,qr,l,mid)) return 1; 39 if(qr>mid&&query(R[u],R[v],ql,qr,mid+1,r)) return 1; 40 return 0; 41 } 42 inline int find(int u,int v,int ql,int qr){ 43 cmax(ql,0),cmin(qr,m); 44 if(ql>qr) return 0; 45 return query(rt[u],rt[v],ql,qr); 46 } 47 int main(){ 48 // freopen("testdata.in","r",stdin); 49 n=read(),q=read(); 50 for(int i=1;i<=n;++i) cmax(m,a[i]=read()); 51 for(int i=1;i<=n;++i) 52 update(rt[i],rt[i-1],a[i]); 53 while(q--){ 54 int b=read(),x=read(),ql=read(),qr=read(),ans=0; 55 for(int i=17;i>=0;--i){ 56 int now=ans+((1^((b>>i)&1))<<i); 57 if(find(ql-1,qr,now-x,now+(1<<i)-1-x)) ans=now; 58 else ans+=((b>>i)&1)<<i; 59 } 60 print(ans^b); 61 } 62 Ot(); 63 return 0; 64 }