RainFestival树
cool_milo
2023-07-19 11:20:44
发现这个有点冷门,写一篇blog推广一下。
感谢教我这个trick的巨佬 @Rainfestival。
~~这个trick好像没有名字,就叫它RainFestival树不过分吧~~
## 问题
十分小清新:给定一个集合 $S$ ,动态加数( $a_i \leq 2^{20}-1$ ),求 $max_{a_i \in S}(b \& a_i)$
## 做法:开桶维护。
考虑两个数相与最大,肯定是从前往后,看每一位是否能够是 $1$ 。
假设我们枚举到第 $j$ 位
如果 $b$ 的第 $j$ 位是 $1$ ,那么 $a_i$ 这一位肯定最好是 $1$,(没有也没办法)
否则 $a_i$ 的这一位没有限制。
但是注意,我们在选择 $a_i$ 的过程中,决策集合在逐渐减小,也就是这一步是 $1$ 不能干扰以前确定是 $1$ 的位,但是更高的位也不全是有限制的。
怎么办呢?
维护一个临时变量 $S$ ,如果现在确定第 $k$ 位是 $1$ ,那么就令 $S \leftarrow S | (1 << k)$
那么我们每次查询第 $j$ 位是否可能是 $1$ ,相当于查询是否 $\exist a_i,a_i | (S | (1 << j)) = a_i$ 。
那么这个问题就可以通过 ~~FMT~~ 解决,但是如果是动态加数,可以通过 ~~CDQ套FMT~~ 解决。
这里有一种常数小且好写的做法,把上述过程想象为 $a_i$ 覆盖它的子集(每个 $a_i$ 会对它的子集产生贡献)。
那么可以想到做法,每次插入一个 $a_i$ 如果它没有被覆盖,就覆盖它,同时枚举 $a_i$ 的每一位删除,递归覆盖。否则被覆盖了,就返回(它的子集一定被覆盖过),这样,每个数只会被覆盖到一次,总复杂度 $\Theta(Q + 2^{20})$ 。
~~讲来讲去就一句话~~
## 例题:最大生成树,每个点有权值,边权为点权按位与。
原题[UOJ176](https://uoj.ac/problem/176)。
考虑 Boruvka (此处略去),那么每轮我们要干的事情是查 $max( \forall a_i \in S,\forall b_i \notin S,a_i \& b_i)$
这里有集合内外之分,但是我们可以魔改之(拜谢bot),把覆盖标记改成染色,每个集合对应一种颜色,如果一个点被当前未被当前集合染色,且颜色数不足两种,那就递归染色,易证每个数只会被染色两次,复杂度 $\Theta((n + 2^{20}) \log n) $ 。