题目大意
对于集合 $a$,定义集合 $S(a)$ 表示集合 $a$ 生成的集合,生成方式为通过以下步骤任意多次:
- 初始,$S(a)=a$;
- 若存在 $x,y \in S(a)$,但是 $x\oplus y \not \in S(a)$,将其插入到 $S(a)$ 中。
现在给定集合 $a,b$,你需要维护一个数据结构,支持以下操作,共 $m$ 次:
- $1\ x$,表示插入 $x$ 到集合 $a$ 中,保证插入之前 $x \not\in a$
- $2\ x$,表示插入 $x$ 到集合 $b$ 中,保证插入之前 $x \not\in b$
- $3\ x$,表示从集合 $a$ 中删除元素 $x$,保证删除之前 $x \in a$
- $4\ x$,表示从集合 $b$ 中删除元素 $x$,保证删除之前 $x \in b$
- $5$,表示询问:输出 $|S(a) \cup S(b)| \bmod 998244353$,即集合并的元素个数
$|a|,|b| \le 10^5,\ \ m \leq 2\times 10^5$,所有的集合元素 $\in [0,2^{63})$
多测,时限比较迷。。反正 $O(n \log^2 x)$ 跑不过
题解
首先,这个 $S(a)$、$S(b)$ 肯定是考虑维护其线性基了。
这里要用到带删除的线性基,删除有在线和离线两种方式,在线是真正地实现删除操作,看这里学一学;离线是计算出每个元素的过期时间,然后线性基插入操作的时候用更新式的插入法,保持基元都是最新的,参考这题。
然后看怎么计算答案。容斥一下有 $ans=|S(a)|+|S(b)|-|S(a) \cap S(b)|$,那怎么算 $|S(a) \cap S(b)|$ 呢?
可以想到两种方法,一是直接求交,拿 $S(a)$ 的每个基元放到 $S(b)$ 里去看看能不能被表示出来,能就说明它是 $S(a)$ 和 $S(b)$ 交空间的基。(qaq为啥我觉得一点都不显然啊) 但这样是 $O(m \log^2 x)$ 的,被卡掉了。
第二种方法是再容斥一下,$S(a) \cap S(b)$ 的基元个数 = $S(a)$ 基元个数 + $S(b)$ 基元个数 - $S(a \cup b)$ 基元个数。(qaq这个也很不显然啊为啥你们就觉得显然了啊) 于是这样就只需要维护三个线性基:$S(a)$、$S(b)$、$S(a) \cup S(b)=S(a\cup b)$,就变成 $O(m \log x)$ 的了。
代码
1 |
|