题解[P7470 岛屿探险]

原题链接

题意
给出一个序列 \(a_{1\dots n},b_{1\dots n}\)
每次查询给出一段区间 \(l,r\) 以及两个数 \(c,d\)
问区间 \([l,r]\) 内有多少个数满足 \(a_i\operatorname{xor}c\leq \min(b_i,d)\)

太久没写 \(\text{cdq}\) 竟还能这么快过掉。

首先,由于询问可加性,区间的限制可以拆为两个 \([1,t]\) 的查询。

于是这就可以以位置为第一维进行 \(\text{cdq}\) 分治了。

然后为了方便地拆掉 \(\min(b_i,d)\),可以将 \(\geq d\)\(b_i\)\(< d\) 的,分开统计。

先是 \(b_i\geq d\)\(i\) ,此时有 \(a_i\operatorname{xor}c\leq d\)。这是 \(\text{01trie}\) 的经典运用。将所有 \(a_i\) 插到 \(\text{01trie}\) 上。查询时在 \(\text{01trie}\) 上按着一条 \(c\operatorname{xor}s=d\) 的链 \(s\) ,这使得前几位 \(\operatorname{xor}c\) 后与 \(d\) 相同。如果这一位上 \(d\)\(1\),则累加上使这一位 \(\operatorname{xor}c=0\) 的数的个数,跳到叶子节点的数的个数同样要算上,此时 \(\operatorname{xor}c=d\)

而对于 \(b_i<d\)\(i\),有 \(a_i\operatorname{xor}c\leq b_i\)。考虑将能使 \(a_i\operatorname{xor}c\leq b_i\)\(c\) 处打上 \(+1\) 的标记。维护一条使 \(s\operatorname{xor}a_i=b_i\) 的链 \(s\),如果这一位上 \(b_i\)\(1\),将 \(\operatorname{xor}a_i\) 后这一位为 \(0\) 的子树打上 \(+1\) 的标记,跳到的叶子节点同样要打上 \(+1\) 的标记。查询时按着 \(c\) 从根开始一路累加被加上的标记和即可。

时间复杂度为 \(O(n\log n\log V)\)\(\text{cdq}\)\(\text{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('\n');
}
posted @ 2021-10-31 13:39  Y_B_X  阅读(35)  评论(0编辑  收藏  举报