题目链接:
给出一个长度为nn的数组CC,回答mm个形式为(L, R, A, B)(L,R,A,B)的询问,含义为存在多少个不同的数组下标k \in [L, R]k∈[L,R]满足C[k] \bigoplus A \geq BC[k]⨁A≥B(式中\bigoplus⨁为异或运算)。
输入描述
输入第一行为一个整数TT,表示一共有TT组测试数据。
对于每组测试数据:
第一行为两个整数nn,mm(1 \leq n, m \leq 500001≤n,m≤50000)。
第二行为nn个整数表示数组CC(0 \leq C[i] \leq 10^{9}0≤C[i]≤109)。
接下来mm行中,第ii行有四个整数L_{i}Li,R_{i}Ri,A_{i}Ai,B_{i}Bi(1 \leq L_{i} \leq R_{i} \leq n1≤Li≤Ri≤n, 0 \leq A_{i}, B_{i} \leq 10^{9}0≤Ai,Bi≤109)。
输出描述
对于每次询问:输出一个整数表示满足条件的数组下标数目。
样例输入
15 21 2 3 4 51 3 1 12 5 2 3
样例输出
22 题意:给出一个数列,然后m个询问,每一询问是问这个区间里面有多少个a[k]^A>=B; 思路:显然是一个莫队,trie树里面存的是当前区间里面的数,所以需要trie的insert和del操作, 然后就是询问这个区间里面有多少个异或大于等于B就贪心就好了,注意最后相等的情况,需要写个query就好; AC代码:
#includeusing namespace std;const int maxn=5e4+10;int n,m,a[maxn],ans[maxn];struct node{ int l,r,a,b,id,sq;}po[maxn];int cmp(node x,node y){ if(x.sq==y.sq)return x.r =0;i--) { int c=((x>>i)&1); if(!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[u][c]=sz++; } u=ch[u][c]; val[u]++; }}inline void Delete(int x){ int u=0,len=30; for(int i=len;i>=0;i--) { int c=((x>>i)&1); u=ch[u][c]; val[u]--; }}inline int query(int A,int B){ int u=0,len=30,sum=0,flag; for(int i=len;i>=0;i--) { int c=((A>>i)&1),d=((B>>i)&1); int ha=u; if(ch[u][1]&&(c^1)>d) { int tep=ch[u][1]; sum=sum+val[tep]; } if(ch[u][0]&&(c^0)>d) { int tep=ch[u][0]; sum=sum+val[tep]; } flag=0; if(ch[u][1]&&(c^1)==d)u=ch[u][1],flag=1; if(ch[u][0]&&(c^0)==d)u=ch[u][0],flag=1; if(ha==u)break; } if(flag)sum=sum+val[u]; return sum;}int main(){ //freopen("in.txt","r",stdin); int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); init(); int sq=sqrt(n*1.0); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&po[i].l,&po[i].r,&po[i].a,&po[i].b); po[i].id=i;po[i].sq=po[i].l/sq; } sort(po+1,po+m+1,cmp); int l=1,r=0; for(int i=1;i<=m;i++) { while(r po[i].r)Delete(a[r]),r--; while(l po[i].l)l--,insert(a[l]); ans[po[i].id]=query(po[i].a,po[i].b); } for(int i=1;i<=m;i++)printf("%d\n",ans[i]); } return 0;}