NOI online 2021 岛屿探险
NOI online 2021 岛屿探险
场上写了个被卡常的时间\(n\log^2 n\),空间 $n\log n $ 做法,洛谷上开O2才能过
我们先考虑对所有\(d_i< b_j\) 计算 \(j\) 对 \(i\) 的贡献。首先可以把询问 \(i\) 拆成
并且和插入一起离线下来按下标的顺序排好序。
那么我们维护一个\(0-1trie\),按顺序把 \(a_j\) 插入\(trie\)中,查询就是从高到低遍历 \(d_i\) 的每一位
如果 \(d_i\) 当前位为0,显然 \(trie\) 上只能走与 \(c_i\) 当前位相同的儿子。
如果 \(d_i\) 当前位为1,对与 \(c_i\) 当前位相同的儿子 \(u0\) 进行子树查询 \(d_i<b_j\)(\(a_j\) 在\(u_0\)子树内) 的个数。因为此时 \(c_i\) 和 \(a_j\) 异或起来这一位比 \(d_i\) 小,后面 \(a_j\) 无论如何取值都符合条件。然后再递归处理与 \(c_i\) 当前位不同的儿子 \(u1\) 。
子树查询可以在\(trie\)树上每个节点开个vector,插入的时候把 \(b_j\) 存到经过的每个节点的\(vector\)上,询问也存在vector上,最后对于每个vector按push进来的顺序用动态开点线段树进行插入和询问。
对 \(d_i\ge b_j\) 的情况,可以当作是对每个 \(b_j\) 计算有多少个 \(b_j\le d_i\) 且 \(c_i\oplus a_j\leq b_j\),也就是交换一下插入和询问,按上面的做法做,然后再反过来考虑每个插入的 \(c_i,d_i\) 会被哪些询问的 \(b_j\) 统计到。也就是在每个vector里把存下来的插入计算出有多少个询问能统计到它,逆序做就行了。
由于一次插入和询问对于trie树上每个节点的vector最多只会push进一个元素,每个vector最多只有n个元素,所以每次计算完一个节点的vector的插入和询问就清空,空间复杂度是 \(n\log n\) 的。总共有 \(n\log n\) 个元素,线段树每次$\log n \(,时间复杂度是\)n\log^2 n$。