【学习笔记】bitset

简介

bitset 是一种高效储存和运算二进制的容器。
时间复杂度与空间复杂度都为 \(O(\frac{n}{w})\),其中 \(w\) 约为 \(32\)

bitset 的声明

\\声明一个大小为 100010 的 bitset
bitset<100010>bs
\\声明一个大小为 5 的 bitset,并将其初始化为 101010(42 的二进制)
\\但是由于 42 的长度大于 5 所以高位会被自动截断
bitset<5>bs(42)

bitset 可以像数组一样用 [] 进行访问,也可以像数组一样更改值,注意 bitset 最低为为 \(0\),且是从右边开始。

bitset 成员函数

单次使用 \(O(1)\) 的成员函数

  • set(pos) 将第 pos 位设为 \(1\)
  • reset(pos) 将第 pos 位设为 \(0\)
  • flip(pos) 翻转第 pos 位。

时间复杂度 \(O(\frac{n}{w})\) 的成员函数

  • set() 将所有位都设置为 1。
  • reset() 将所有位都设置为 0。
  • flip() 翻转所有位。
  • count() 返回值为 1 的位的数量。
  • size() 返回 bitset 的总大小。
  • any() 检查是否有任何一位是 1。
  • none() 检查是否所有位都是 0。
  • all() 检查是否所有位都是 1。

位运算(时间复杂度 \(O(\frac{n}{w})\))

bitset 重载了常见的位运算符,可以方便地在两个 大小相同 的 bitset 之间进行运算。

  • & (与)
  • | (或)
  • ^ (异或)
  • ~(非)
  • <<(左移)
  • >> (右移)

例题cf878d

考虑只有 \(0,1\) 的情况:显然可以对 \(k\) 种生物,每种生物 \(i\) 都开一个大小为 \(n\) 的 bitset \(b_i\)\(\max(x,y)\) 操作就是 \(b_x | b_y\)\(\min(x,y)\) 操作就是 \(b_x \& b_y\)

拓展到一般情况:可以将 \(n\) 列的 \(k\) 个数字离散化到 \(1\sim k\) 的值域当中。假设 \(a_{i,j}=v\),可以将它变成 \(2^v - 1\),存到 bitset 中,这样原来的 \(nk\) 个数就以 \(0,1\) 的形式存到了 \(nk^2\) 大小的 bitset 中(每个数占用 \(k\) 大小的 bitset,有 \(nk\) 个数),这样就可以继续用 bitset 维护。时间复杂度 \(O(nkq/\omega+nk^2)\)

考虑优化:发现维护了很多冗余的信息,因为最多只有 \(2^k\) 个本质不同的列,但是现在实际上维护了 \(nk\) 个列。考虑两个相同的列,不管怎么操作它们都还是相同的,因此不管如何操作,最后本质不同的列还是只有 \(2^k\)

可以先预处理出 \(k\times 2^k\) 大小的 bitset,每次操作就把两个大小为 \(2^k\) 的 bitset 进行位运算,将新生成的一个 bitset 放到下面。设 \(id_{i,j}\) 表示第 \(i\) 大列,第 \(j\) 小列的类型(共 \(n\) 大列,每一大列有 \(k\) 小列),如果要查询 \(a_{i,j}\) 的值,可以先算出出 \(\sum_{s = 1}^k b_{i,id_{j,s}}\) 即可,即是第几大的数,然后在映射回离散化前的数值。时间复杂度 \(O(2 ^ kq/\omega + k/\omega)\)

posted @ 2025-08-18 16:53  GuoSN0410  阅读(41)  评论(0)    收藏  举报