a01sa01to's competitive programming library. Requires C++20 or higher with GCC. This documentation is automatically generated by online-judge-tools/verification-helper
#include "library/data-structure/dynamic-bitset.hpp"Bitset の動的版。
基本的には (static な) bitset と同じように扱える ([] アクセスと to_ull() 以外)
DynamicBitset(n): $n$ ビットの Dynamic Bitset を生成。DynamicBitset(n, x): 数値 $x$ から $n$ ビットの Dynamic Bitset を生成。&=|=^=<<=>>=~==!=<<>>&|^set(): 全ビットを 1 にする。set(i, true): $i$ 番目のビットを 1 にする。set(i, false): $i$ 番目のビットを 0 にする。reset(): 全ビットを 0 にする。reset(i): $i$ 番目のビットを 0 にする。flip(): 全ビットを反転する。count(): popcountsize(): ビット数を返す。test(i): $i$ 番目のビットの値を返す。all(): 全てのビットが 1 なら true を返す。any(): 1 つでもビットが 1 なら true を返す。none(): 全てのビットが 0 なら true を返す。to_ull(): ビット列を unsigned long long に変換する。to_string(): ビット列を文字列に変換する。#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