题解[P7470 岛屿探险]

原题链接

题意
给出一个序列 (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('
');
}
原文地址:https://www.cnblogs.com/Y-B-X/p/15489257.html