[NOI Online 2021 提高组] 岛屿探险 题解

题意简述

  • 一行 nn 对数,第 ii 对数为权值对 <ai,bi><a_i,b_i>
  • 回答 qq 个询问 <lj,rj,cj,dj><l_j,r_j,c_j,d_j>,询问的是在 ljl_jrjr_j 内所有数对中满足 aixorcjmin(bi,dj)a_i\operatorname{xor} c_j\leq\min(b_i,d_j) 的数对个数。
  • 1n,q1051\leq n,q\leq 10^51ljrjn1\leq l_j\leq r_j\leq n0ai,bi,cj0\leq a_i, b_i, c_j, dj2241d_j\leq 2^{24} - 1

解法

​ 先考虑一个询问怎么求。

​ 看到异或就知道大概是要建 0-1 trie 的。对于一个询问,分 bidjb_i\geq d_jbi<djb_i<d_j 两种情况考虑。

​ 对于 bidjb_i\geq d_j 的情况,要求即为 aixorcjdja_i\operatorname{xor} c_j\leq d_j ,以 aia_i 为权值建出序列的 0-1 trie。

​ 令 cjc_j 从高位往低位走,对于一个节点(假设 cjc_j 当前位为 00)有 0011 两个儿子:若 djd_j 当前位为 11,则 00 儿子及其子树一定可行,11 儿子可能可行,向 11 递归;反之 11 儿子一定不可行,向 00 递归。这一部分是 0-1 trie 经典问题,不再赘述。

​ 对于 bi<djb_i< d_j 的情况,要求即为 aixorcjbia_i\operatorname{xor} c_j\leq b_i

​ 分析一下各种情况,这里还是假设 cjc_j 当前位为 00

  • aia_i 当前位为 00bib_i 当前位为 00:可能可行,需向下递归。
  • aia_i 当前位为 00bib_i 当前位为 11一定可行,子树全部可行。
  • aia_i 当前位为 11bib_i 当前位为 00一定不可行,子树全部不可行。
  • aia_i 当前位为 11bib_i 当前位为 11:可能可行,需向下递归。

​ 观察发现:aixorbi=0a_i\operatorname{xor}b_i=0 时需要向下递归,否则要么全可行,要么全不可行。

​ 对 cjc_j 当前位为 11 的情况分析类似。

aixorbia_i\operatorname{xor}b_i 为权值建出序列的 0-1 trie,再在每个节点记录其子树内 ai=0a_i=011 的数的个数。查询时令 cjc_j 从高位往低位走,按上面的讨论做即可。

​ 再考虑原问题。按 bi,djb_i,d_j 排序,顺着扫一遍,分块维护两组 trie 树:一组是关于 bidjb_i\geq d_j 的,另一组是关于 bi<djb_i< d_j 的,扫的时候在 trie 上动态加点删点即可。

​ 设块长为 BB,值域为 AA,时间复杂度 O(nlogA+Q(nBlogA+B))O(n\log A+Q(\frac{n}{B}\log A+B))n,Qn,Q 同级,理论取 B=nlognB=\sqrt{n\log n},实践中设 B=20003000B=2000\sim 3000 时最优。空间 O(nlogA)O(n\log A)

较小的常数使得分块做法的通过成为可能。

CDQ 分治之类的做法(似乎)也可以类似地套用。按 bi,djb_i,d_j 排序,分治时左区间对右区间的贡献即所有 bib_i 的插入(bi<djb_i< d_j 部分的 trie 树上)和删除( bidjb_i\geq d_j 的 trie 树上)。其它题解里有这方面的详细讲解。

​ 不济的话把分块(时间被卡)和树套树(空间被卡)结合一下把块长调大一点也能过。

​ 放一下关键位置的源代码(bi<djb_i< d_j 部分的 trie 树建立与查询):

void trieadd1(int u,int aa,int bb,int np){
	if(!np)return;
	int ng=(((aa^bb)&(1<<(np-1)))>>(np-1));
	if(!son[u][ng])son[u][ng]=++pb;
	dq[son[u][ng]][(aa&(1<<np-1))>>(np-1)]++;
	trieadd1(son[u][ng],aa,bb,np-1);
}
int triereq1(int u,int x,int np){
	if(!u)return 0;
	if(!np)return dq[u][0]+dq[u][1];
	int ng=((x&(1<<(np-1)))>>(np-1));
	return triereq1(son[u][ng],x,np-1)+dq[son[u][ng^1]][ng];
}