NOI online 2021 岛屿探险

NOI online 2021 岛屿探险

场上写了个被卡常的时间\(n\log^2 n\),空间 $n\log n $ 做法,洛谷上开O2才能过

我们先考虑对所有\(d_i< b_j\) 计算 \(j\)\(i\) 的贡献。首先可以把询问 \(i\) 拆成

\[\sum_{j=1}^{r_i} (a_j\oplus c_i)\le d_i - \sum_{j=1}^{l_i-1} (a_j\oplus c_i)\le d_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$。

posted @ 2021-03-27 16:02  lcyfrog  阅读(128)  评论(0编辑  收藏  举报