这道题的简化版是没有加d的。如果是那样的话,我们只需要做一个可持久化trie树就好了。把要异或的数划分为二进制,从高位向低位匹配,如果当前位为0,我们查询区间内的数当前位能否为1;如果当前位为1,我们查询区间内的数当前位能否为0。具体来说,假设现在已经匹配了x(这个x是拿来与b匹配的x而不是匹配后的值),现在要匹配第h位,并且b的第h位为1,我们要确定当前位能否为0,其实就是找【x,x+2^h-1】这个区间内的siz是否大于0。h位为0,同理。那么它加了一个d的话,好办,只需要把原来那个区间同时减去d就好了。
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; const int M=1e6+10; const int sz=262144; int n,m,now,tot,ls[M],rs[M],a[N],sum[M],rt[N]; void update(int pre,int &o,int l,int r,int x){ o=++tot;ls[o]=ls[pre];rs[o]=rs[pre]; sum[o]=sum[pre]+1; if(l==r) return ; int mid=l+r>>1; if(x<mid) update(ls[pre],ls[o],l,mid,x); else update(rs[pre],rs[o],mid+1,r,x); } int query(int last,int now,int l,int r,int L,int R){ if(l>=L&&r<=R) return sum[now]-sum[last]; if(r<L||l>R) return 0; int mid=l+r>>1; return query(ls[last],ls[now],l,mid,L,R)+query(rs[last],rs[now],mid+1,r,L,R); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); update(rt[i-1],rt[i],1,sz,a[i]); } for(int i=1;i<=m;++i){ int b,d,l,r;scanf("%d%d%d%d",&b,&d,&l,&r); now=0; for(int k=17;k>=0;--k){ if(b&(1<<k)){ if(query(rt[l-1],rt[r],1,sz,max(0,now-d),max(0,now+(1<<k)-1-d))<=0) if(query(rt[l-1],rt[r],1,sz,max(0,now+(1<<k)-d),max(0,now+(1<<(k+1))-1-d))>0) now+=1<<k; }else{ if(query(rt[l-1],rt[r],1,sz,max(0,now+(1<<k)-d),max(0,now+(1<<(k+1))-1-d))>0) now+=1<<k; } } printf("%d\n",now^b); } return 0; }