题意
给出一个序列 (a_{1dots n},b_{1dots n}),
每次查询给出一段区间 (l,r) 以及两个数 (c,d),
问区间 ([l,r]) 内有多少个数满足 (a_ioperatorname{xor}cleq min(b_i,d))。
太久没写 ( ext{cdq}) 竟还能这么快过掉。
首先,由于询问可加性,区间的限制可以拆为两个 ([1,t]) 的查询。
于是这就可以以位置为第一维进行 ( ext{cdq}) 分治了。
然后为了方便地拆掉 (min(b_i,d)),可以将 (geq d) 的 (b_i) 与 (< d) 的,分开统计。
先是 (b_igeq d) 的 (i) ,此时有 (a_ioperatorname{xor}cleq d)。这是 ( ext{01trie}) 的经典运用。将所有 (a_i) 插到 ( ext{01trie}) 上。查询时在 ( ext{01trie}) 上按着一条 (coperatorname{xor}s=d) 的链 (s) ,这使得前几位 (operatorname{xor}c) 后与 (d) 相同。如果这一位上 (d) 为 (1),则累加上使这一位 (operatorname{xor}c=0) 的数的个数,跳到叶子节点的数的个数同样要算上,此时 (operatorname{xor}c=d)。
而对于 (b_i<d) 的 (i),有 (a_ioperatorname{xor}cleq b_i)。考虑将能使 (a_ioperatorname{xor}cleq b_i) 的 (c) 处打上 (+1) 的标记。维护一条使 (soperatorname{xor}a_i=b_i) 的链 (s),如果这一位上 (b_i) 为 (1),将 (operatorname{xor}a_i) 后这一位为 (0) 的子树打上 (+1) 的标记,跳到的叶子节点同样要打上 (+1) 的标记。查询时按着 (c) 从根开始一路累加被加上的标记和即可。
时间复杂度为 (O(nlog nlog V)),( ext{cdq}) 与 ( ext{01trie}) 各带一个 (log)。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,K=24;
int n,m,x,y,l,r,a,b,tot,t_tot,rt,tmp;
int res[N];bool bx,bw;char ch;
inline void read(int &x){
x=0;ch=getchar();while(ch<48)ch=getchar();
while(ch>47)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}
void write(int x){if(x>9)write(x/10);putchar(48+x%10);}
struct cdq{
int i,a,b,id;char opt;cdq()=default;//opt=0:mdf otherwise:inq
cdq(int _i,int _a,int _b,char _opt=0,int _id=0)
:i(_i),a(_a),b(_b),opt(_opt),id(_id){}
}q[N],q0[N],qq[N],qq0[N];//min=d for q ; min=b for qq
bool cmpi(cdq x,cdq y){return x.i^y.i?x.i<y.i:!x.opt;}
bool cmpq(cdq x,cdq y){return x.b^y.b?x.b>y.b:!x.opt;}
bool cmpqq(cdq x,cdq y){return x.b^y.b?x.b<y.b:x.opt;}
struct trie01{int son[2],tag[2],sz;}t[N*(K+1)];
void update(int &k,int x,int i,int v){
if(!k)k=++t_tot;t[k].sz+=v;
if(~i)update(t[k].son[(x>>i)&1],x,i-1,v);
}
void update(int &k,int x,int w,int i,int v){
if(!k)k=++t_tot;
bw=(w>>i)&1;bx=bw^((x>>i)&1);
if(~i){
if(bw)t[k].tag[!bx]+=v;
update(t[k].son[bx],x,w,i-1,v);
}
else t[k].tag[0]+=v;
}
void inquiry(int k,int x,int w,int i){
if(~i){
bw=(w>>i)&1;bx=bw^((x>>i)&1);
if(bw)tmp+=t[t[k].son[!bx]].sz;
inquiry(t[k].son[bx],x,w,i-1);
}
else tmp+=t[k].sz;
}
void inquiry(int k,int x,int i){
if(~i){
bx=(x>>i)&1;tmp+=t[k].tag[bx];
inquiry(t[k].son[bx],x,i-1);
}
else tmp+=t[k].tag[0];
}
void solve(int l,int r){
if(l^r){
int mid=(l+r)>>1,i;
solve(l,mid);solve(mid+1,r);
merge(q+l,q+mid+1,q+mid+1,q+r+1,q0+l,cmpq);
merge(qq+l,qq+mid+1,qq+mid+1,qq+r+1,qq0+l,cmpqq);
for(i=l;i<=r;++i)q[i]=q0[i],qq[i]=qq0[i];
for(i=l;i<=r;++i){
if(q[i].i<=mid&&!q[i].opt)update(rt,q[i].a,K,1);
else if(q[i].i>mid&&q[i].opt){
tmp=0;inquiry(rt,q[i].a,q[i].b,K);
res[q[i].id]+=tmp*q[i].opt;
}
}
for(i=l;i<=r;++i)if(q[i].i<=mid&&!q[i].opt)update(rt,q[i].a,K,-1);
for(i=l;i<=r;++i){
if(qq[i].i<=mid&&!qq[i].opt)update(rt,qq[i].a,qq[i].b,K,1);
else if(qq[i].i>mid&&qq[i].opt){
tmp=0;inquiry(rt,qq[i].a,K);
res[qq[i].id]+=tmp*qq[i].opt;
}
}
for(i=l;i<=r;++i)if(qq[i].i<=mid&&!qq[i].opt)update(rt,qq[i].a,qq[i].b,K,-1);
}
}
main(){
read(n);read(m);register int i;
for(i=1;i<=n;++i)read(a),read(b),q[++tot]=cdq(i,a,b);
for(i=1;i<=m;++i){
read(l),read(r),read(a),read(b);
q[++tot]=cdq(r,a,b,1,i);
if(l>1)q[++tot]=cdq(l-1,a,b,-1,i);
}
sort(q+1,q+tot+1,cmpi);
for(i=1;i<=tot;++i)q[i].i=i;
for(i=1;i<=tot;++i)qq[i]=q[i];
solve(1,tot);
for(i=1;i<=m;++i)write(res[i]),putchar('
');
}