Asa's CP Library

a01sa01to's competitive programming library. Requires C++20 or higher with GCC. This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub a01sa01to/cp-library

:heavy_check_mark: Dynamic Bitset
(library/data-structure/dynamic-bitset.hpp)

Bitset の動的版。

使い方

基本的には (static な) bitset と同じように扱える ([] アクセスと to_ull() 以外)

演算子系

メンバ関数

Verified with

Code

#pragma once

#include <algorithm>
#include <bit>
#include <cassert>
#include <concepts>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <vector>
using namespace std;

namespace asalib::ds {
  class DynamicBitset {
    int siz = 0;
    vector<uint64_t> bits;

    public:
    constexpr explicit DynamicBitset() = default;
    constexpr DynamicBitset(const DynamicBitset&) = default;
    constexpr ~DynamicBitset() = default;
    constexpr DynamicBitset& operator=(const DynamicBitset&) = default;
    constexpr explicit DynamicBitset(const int size) {
      siz = size;
      bits.reserve((size + 63) >> 6);
      bits.resize((size + 63) >> 6, 0);
    }
    template<integral T>
    constexpr explicit DynamicBitset(const int size, const T value) {
      // TODO: ほかの型も考慮する
      static_assert(sizeof(T) <= sizeof(uint64_t), "DynamicBitset: value type too large");
      siz = size;
      bits.reserve((size + 63) >> 6);
      bits.resize((size + 63) >> 6, 0);
      bits[0] = static_cast<uint64_t>(value);
      trim();
    }

    constexpr DynamicBitset& operator&=(const DynamicBitset& other) {
      assert(siz == other.siz);
      const int sz = bits.size();
      for (int i = 0; i < sz; ++i) bits[i] &= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator|=(const DynamicBitset& other) {
      assert(siz == other.siz);
      const int sz = bits.size();
      for (int i = 0; i < sz; ++i) bits[i] |= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator^=(const DynamicBitset& other) {
      assert(siz == other.siz);
      const int sz = bits.size();
      for (int i = 0; i < sz; ++i) bits[i] ^= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator<<=(const int shift) {
      if (shift == 0) return *this;
      const int full = shift >> 6;
      const int rem = shift & 63;
      const int sz = bits.size();
      if (full >= sz) {
        ranges::fill(bits, 0);
        return *this;
      }
      if (rem == 0) {
        for (int i = sz - 1; i >= full; --i) bits[i] = bits[i - full];
        ranges::fill(bits.begin(), bits.begin() + full, 0);
      }
      else {
        for (int i = sz - 1; i >= full; --i) {
          bits[i] = bits[i - full] << rem;
          if (i - full - 1 >= 0) bits[i] |= bits[i - full - 1] >> (64 - rem);
        }
        ranges::fill(bits.begin(), bits.begin() + full, 0);
      }
      trim();
      return *this;
    }
    constexpr DynamicBitset& operator>>=(const int shift) {
      if (shift == 0) return *this;
      const int full = shift >> 6;
      const int rem = shift & 63;
      const int sz = bits.size();
      if (full >= sz) {
        ranges::fill(bits, 0);
        return *this;
      }
      if (rem == 0) {
        for (int i = 0; i < sz - full; ++i) bits[i] = bits[i + full];
        ranges::fill(bits.end() - full, bits.end(), 0);
      }
      else {
        for (int i = 0; i < sz - full; ++i) {
          bits[i] = bits[i + full] >> rem;
          if (i + full + 1 < sz) bits[i] |= bits[i + full + 1] << (64 - rem);
        }
        ranges::fill(bits.end() - full, bits.end(), 0);
      }
      return *this;
    }
    constexpr DynamicBitset& set() {
      for (int i = 0; i < ranges::ssize(bits); ++i) bits[i] = ~0ULL;
      trim();
      return *this;
    }
    constexpr DynamicBitset& set(const int pos, const bool val = true) {
      if (pos >= siz) throw out_of_range("DynamicBitset::set: position out of range");
      const int idx = pos >> 6;
      const int bit = pos & 63;
      if (val)
        bits[idx] |= (1ULL << bit);
      else
        bits[idx] &= ~(1ULL << bit);
      return *this;
    }
    constexpr DynamicBitset& reset() {
      ranges::fill(bits, 0);
      return *this;
    }
    constexpr DynamicBitset& reset(const int pos) { return set(pos, false); }
    constexpr DynamicBitset operator~() const {
      DynamicBitset res = *this;
      res.flip();
      return res;
    }
    constexpr DynamicBitset& flip() {
      for (int i = 0; i < ranges::ssize(bits); ++i) bits[i] = ~bits[i];
      trim();
      return *this;
    }
    constexpr DynamicBitset& flip(const int pos) {
      if (pos >= siz) throw out_of_range("DynamicBitset::flip: position out of range");
      const int idx = pos >> 6;
      const int bit = pos & 63;
      bits[idx] ^= (1ULL << bit);
      return *this;
    }

    constexpr int count() const {
      int cnt = 0;
      for (const uint64_t& b : bits) cnt += popcount(b);
      return cnt;
    }
    constexpr int size() const { return siz; }
    constexpr bool test(const int pos) const {
      if (pos >= siz) throw out_of_range("DynamicBitset::test: position out of range");
      const int idx = pos >> 6;
      const int bit = pos & 63;
      return (bits[idx] >> bit) & 1;
    }
    constexpr bool all() const {
      for (const uint64_t& b : bits)
        if (b != ~0ULL) return false;
      return true;
    }
    constexpr bool any() const {
      for (const uint64_t& b : bits)
        if (b != 0) return true;
      return false;
    }
    constexpr bool none() const {
      for (const uint64_t& b : bits)
        if (b != 0) return false;
      return true;
    }
    constexpr uint64_t to_ull() const {
      if (bits.size() > 1) throw logic_error("DynamicBitset::to_ull: overflow");
      if (bits.empty()) return 0;
      return bits[0];
    }
    constexpr string to_string() const {
      string res;
      res.reserve(siz);
      for (int i = 0; i < siz; ++i) res += (test(i) ? '1' : '0');
      ranges::reverse(res);
      return res;
    }

    constexpr bool operator==(const DynamicBitset& other) const {
      if (siz != other.siz) return false;
      for (int i = 0; i < ranges::ssize(bits); ++i)
        if (bits[i] != other.bits[i]) return false;
      return true;
    }
    constexpr bool operator!=(const DynamicBitset& other) const {
      return !(*this == other);
    }
    constexpr DynamicBitset operator<<(const uint64_t shift) const {
      DynamicBitset res = *this;
      res <<= shift;
      return res;
    }
    constexpr DynamicBitset operator>>(const uint64_t shift) const {
      DynamicBitset res = *this;
      res >>= shift;
      return res;
    }
    constexpr DynamicBitset operator&(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res &= other;
      return res;
    }
    constexpr DynamicBitset operator|(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res |= other;
      return res;
    }
    constexpr DynamicBitset operator^(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res ^= other;
      return res;
    }

    private:
    constexpr void trim() {
      if (const int rem = siz & 63; rem != 0 && !bits.empty()) bits.back() &= (1ULL << rem) - 1;
    }
  };
}  // namespace asalib::ds
#line 2 "library/data-structure/dynamic-bitset.hpp"

#include <algorithm>
#include <bit>
#include <cassert>
#include <concepts>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <vector>
using namespace std;

namespace asalib::ds {
  class DynamicBitset {
    int siz = 0;
    vector<uint64_t> bits;

    public:
    constexpr explicit DynamicBitset() = default;
    constexpr DynamicBitset(const DynamicBitset&) = default;
    constexpr ~DynamicBitset() = default;
    constexpr DynamicBitset& operator=(const DynamicBitset&) = default;
    constexpr explicit DynamicBitset(const int size) {
      siz = size;
      bits.reserve((size + 63) >> 6);
      bits.resize((size + 63) >> 6, 0);
    }
    template<integral T>
    constexpr explicit DynamicBitset(const int size, const T value) {
      // TODO: ほかの型も考慮する
      static_assert(sizeof(T) <= sizeof(uint64_t), "DynamicBitset: value type too large");
      siz = size;
      bits.reserve((size + 63) >> 6);
      bits.resize((size + 63) >> 6, 0);
      bits[0] = static_cast<uint64_t>(value);
      trim();
    }

    constexpr DynamicBitset& operator&=(const DynamicBitset& other) {
      assert(siz == other.siz);
      const int sz = bits.size();
      for (int i = 0; i < sz; ++i) bits[i] &= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator|=(const DynamicBitset& other) {
      assert(siz == other.siz);
      const int sz = bits.size();
      for (int i = 0; i < sz; ++i) bits[i] |= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator^=(const DynamicBitset& other) {
      assert(siz == other.siz);
      const int sz = bits.size();
      for (int i = 0; i < sz; ++i) bits[i] ^= other.bits[i];
      return *this;
    }
    constexpr DynamicBitset& operator<<=(const int shift) {
      if (shift == 0) return *this;
      const int full = shift >> 6;
      const int rem = shift & 63;
      const int sz = bits.size();
      if (full >= sz) {
        ranges::fill(bits, 0);
        return *this;
      }
      if (rem == 0) {
        for (int i = sz - 1; i >= full; --i) bits[i] = bits[i - full];
        ranges::fill(bits.begin(), bits.begin() + full, 0);
      }
      else {
        for (int i = sz - 1; i >= full; --i) {
          bits[i] = bits[i - full] << rem;
          if (i - full - 1 >= 0) bits[i] |= bits[i - full - 1] >> (64 - rem);
        }
        ranges::fill(bits.begin(), bits.begin() + full, 0);
      }
      trim();
      return *this;
    }
    constexpr DynamicBitset& operator>>=(const int shift) {
      if (shift == 0) return *this;
      const int full = shift >> 6;
      const int rem = shift & 63;
      const int sz = bits.size();
      if (full >= sz) {
        ranges::fill(bits, 0);
        return *this;
      }
      if (rem == 0) {
        for (int i = 0; i < sz - full; ++i) bits[i] = bits[i + full];
        ranges::fill(bits.end() - full, bits.end(), 0);
      }
      else {
        for (int i = 0; i < sz - full; ++i) {
          bits[i] = bits[i + full] >> rem;
          if (i + full + 1 < sz) bits[i] |= bits[i + full + 1] << (64 - rem);
        }
        ranges::fill(bits.end() - full, bits.end(), 0);
      }
      return *this;
    }
    constexpr DynamicBitset& set() {
      for (int i = 0; i < ranges::ssize(bits); ++i) bits[i] = ~0ULL;
      trim();
      return *this;
    }
    constexpr DynamicBitset& set(const int pos, const bool val = true) {
      if (pos >= siz) throw out_of_range("DynamicBitset::set: position out of range");
      const int idx = pos >> 6;
      const int bit = pos & 63;
      if (val)
        bits[idx] |= (1ULL << bit);
      else
        bits[idx] &= ~(1ULL << bit);
      return *this;
    }
    constexpr DynamicBitset& reset() {
      ranges::fill(bits, 0);
      return *this;
    }
    constexpr DynamicBitset& reset(const int pos) { return set(pos, false); }
    constexpr DynamicBitset operator~() const {
      DynamicBitset res = *this;
      res.flip();
      return res;
    }
    constexpr DynamicBitset& flip() {
      for (int i = 0; i < ranges::ssize(bits); ++i) bits[i] = ~bits[i];
      trim();
      return *this;
    }
    constexpr DynamicBitset& flip(const int pos) {
      if (pos >= siz) throw out_of_range("DynamicBitset::flip: position out of range");
      const int idx = pos >> 6;
      const int bit = pos & 63;
      bits[idx] ^= (1ULL << bit);
      return *this;
    }

    constexpr int count() const {
      int cnt = 0;
      for (const uint64_t& b : bits) cnt += popcount(b);
      return cnt;
    }
    constexpr int size() const { return siz; }
    constexpr bool test(const int pos) const {
      if (pos >= siz) throw out_of_range("DynamicBitset::test: position out of range");
      const int idx = pos >> 6;
      const int bit = pos & 63;
      return (bits[idx] >> bit) & 1;
    }
    constexpr bool all() const {
      for (const uint64_t& b : bits)
        if (b != ~0ULL) return false;
      return true;
    }
    constexpr bool any() const {
      for (const uint64_t& b : bits)
        if (b != 0) return true;
      return false;
    }
    constexpr bool none() const {
      for (const uint64_t& b : bits)
        if (b != 0) return false;
      return true;
    }
    constexpr uint64_t to_ull() const {
      if (bits.size() > 1) throw logic_error("DynamicBitset::to_ull: overflow");
      if (bits.empty()) return 0;
      return bits[0];
    }
    constexpr string to_string() const {
      string res;
      res.reserve(siz);
      for (int i = 0; i < siz; ++i) res += (test(i) ? '1' : '0');
      ranges::reverse(res);
      return res;
    }

    constexpr bool operator==(const DynamicBitset& other) const {
      if (siz != other.siz) return false;
      for (int i = 0; i < ranges::ssize(bits); ++i)
        if (bits[i] != other.bits[i]) return false;
      return true;
    }
    constexpr bool operator!=(const DynamicBitset& other) const {
      return !(*this == other);
    }
    constexpr DynamicBitset operator<<(const uint64_t shift) const {
      DynamicBitset res = *this;
      res <<= shift;
      return res;
    }
    constexpr DynamicBitset operator>>(const uint64_t shift) const {
      DynamicBitset res = *this;
      res >>= shift;
      return res;
    }
    constexpr DynamicBitset operator&(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res &= other;
      return res;
    }
    constexpr DynamicBitset operator|(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res |= other;
      return res;
    }
    constexpr DynamicBitset operator^(const DynamicBitset& other) const {
      DynamicBitset res = *this;
      res ^= other;
      return res;
    }

    private:
    constexpr void trim() {
      if (const int rem = siz & 63; rem != 0 && !bits.empty()) bits.back() &= (1ULL << rem) - 1;
    }
  };
}  // namespace asalib::ds
Back to top page