介绍
莫号模板库(Mohao's Template Folder, MTF)是一个由我个人创建个人使用不欢迎贡献的算法竞赛模板库。
主要的设计灵感来自于 AtCoder Library 以及 WIDA 的 XCPC 模板库。
目前正在施工中……
约定
- C++ 版本:
- 最低支持版本:
c++17; - 默认版本:
gnu++23;
- 最低支持版本:
- 格式:
- 缩进宽度为 4 个空格;
- 大括号换行;
- 一元运算符不空格,其他运算符空一格;
- 命名:
- 遵循
GoLang的命名规范;
- 遵循
- 其他:
- 使用邻接表存图;
- 使用
0-indexed的左闭右闭区间; - 使用解绑同步流的
std::cin和std::cout输入输出; - 使用
using namespace std;,非必要不使用#define int long long; - 使用局部变量而非全局变量,局部
lambda而非全局函数; - 使用
emplace而非push,使用contains而非count; - 若键值较小,使用
vector而非map;不要求顺序的情况下可以用unordered_系列,但在 Codeforces 上记得使用随机模数;
初始代码
#include <bits/stdc++.h>
using namespace std;
signed main() {
}
auto FAST_IO = cin.tie(nullptr)->sync_with_stdio(false);
随机哈希
struct custom_hash {
static u64 splitmix64(u64 x) {
x += 0x9e3779b97f4a7c15;
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
return x ^ (x >> 31);
}
u64 operator()(u64 x) const {
static const u64 SEED =
std::chrono::high_resolution_clock::now().time_since_epoch().count();
return splitmix64(x + SEED);
}
};
二分答案
int l, r, ans;
bool check(int);
while (l <= r) {
int mid = l + (r - l) / 2;
if (check(mid)) {
ans = mid;
// l 和 r 取决于方向
l = mid + 1;
} else {
r = mid - 1;
}
}
Lambda 递归
// C++23
auto dfs1 = [&](this auto &&self, int x, int p) -> void {
for (auto y : adj[x]) {
if (y == p)
continue;
self(y, x);
}
};
// C++17
std::function<void(int, int)> dfs2 = [&](int x, int p) {
for (auto y : adj[x]) {
if (y == p)
continue;
dfs2(y, x);
}
};
线性筛 (Sieve)
inline void Sieve(int n, auto &&pri, auto &&mp) {
mp.resize(n + 1);
for (int i = 2; i <= n; i++) {
if (!mp[i])
pri.emplace_back(i);
for (int p : pri) {
if (i * p > n)
break;
mp[i * p] = p;
if (i % p == 0)
break;
}
}
}
快速幂
inline int PowMod(i64 a, i64 b, int p) {
i64 res = 1;
while (b) {
if (b & 1) res = res * a % p;
b = b >> 1;
a = a * a % p;
}
return res;
}
因数/约数分解
inline auto Factor(int n) {
std::vector<std::pair<int, int>> res;
for (int i = 2; i * i <= n; i++) {
int cur = 0;
while (n % i == 0) {
cur++;
n /= i;
}
if (cur != 0)
res.emplace_back(i, cur);
}
if (n > 1)
res.emplace_back(n, 1);
return res;
}
inline auto Divisor(int n) {
std::vector<int> res;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
res.emplace_back(i);
if (i * i != n)
res.emplace_back(n / i);
}
}
std::sort(res.begin(), res.end());
return res;
}
扩展欧几里得 (ExGCD)
inline auto ExGCD(auto a, auto b, auto &x, auto &y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
auto d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
并查集 (DSU)
struct DSU {
std::vector<int> f, sz;
DSU(int n) : f(n), sz(n, 1) { std::iota(f.begin(), f.end(), 0); }
int Find(int x) {
while (x != f[x])
x = f[x] = f[f[x]];
return x;
}
void Merge(int x, int y) {
x = Find(x), y = Find(y);
if (x == y)
return;
f[y] = x;
sz[x] += sz[y];
}
};
树状数组 (Fenwick)
template <typename T> struct Fenwick {
int n;
std::vector<T> a;
Fenwick(int n) : n(n), a(n + 1) {}
void Add(int x, T v) {
for (; x <= n; x += x & -x)
a[x] += v;
}
T sum(int x) {
T res = {};
for (; x; x -= x & -x)
res += a[x];
return res;
}
T Sum(int l, int r) { return sum(r) - sum(l - 1); }
};
线段树 (SegTree)
关于 S 的约束:
- 存在满足封闭性结合律的
operator+运算; - 存在单位元
{}(具有默认构造函数,且满足和单位元运算后不改变原值)
关于初始数组 vector<T>:
- 若
T\(\neq\)S,则必须保证S存在可由T构造的构造函数。
template <class S>
struct SegTree {
int n;
std::vector<S> tr;
SegTree(int n, const S &e) {
build(n, std::vector<S>(n, e));
}
SegTree(auto &&l, auto &&r) {
build(r - l, l);
}
void build(int m, auto &&arr) {
for (n = 1; n < m; n <<= 1);
tr.resize(n << 1);
for (int i = 0; i < m; i++)
tr[i + n] = arr[i];
for (int i = n - 1; i >= 1; i--)
pull(i);
}
void pull(int k) {
tr[k] = tr[k << 1] + tr[k << 1 | 1];
}
void Set(int p, const S &x) {
p += n;
tr[p] = x;
for (p >>= 1; p; p >>= 1)
pull(p);
}
S Get(int p) {
return tr[p + n];
}
S Query(int l, int r) {
l += n, r += n;
S sml{}, smr{};
while (l < r) {
if (l & 1)
sml = sml + tr[l++];
if (r & 1)
smr = tr[--r] + smr;
l >>= 1;
r >>= 1;
}
return sml + smr;
}
};
懒标记线段树
关于 F 的约束:
- 存在满足封闭性的
operator+=运算; - 存在一个恒等映射
{}(默认构造函数); - 存在运算
operator==判断是否和恒等映射相等;- 其实这里也不是非常必要的,但是可以提高性能;
关于 S 的约束:
- 存在满足封闭性结合律的
operator+运算; - 存在单位元
{}(具有默认构造函数,且满足和单位元运算后不改变原值) - 存在
operator*=运算满足将映射F应用于S返回一个S,并且满足分配律。
关于初始数组 vector<T>:
- 若
T\(\neq\)S,则必须保证S存在可由T构造的构造函数。
template<class S, class F>
struct LazySegTree {
int n, h;
std::vector<S> tr;
std::vector<F> lz;
LazySegTree(int n, const S &e) {
build(n, std::vector<S>(n, e));
}
LazySegTree(auto &&l, auto &&r) {
build(r - l, l);
}
void build(int m, auto &&arr) {
for (n = 1; n < m; n <<= 1);
h = __builtin_ctz(n);
tr.resize(n << 1);
lz.resize(n);
for (int i = 0; i < m; i++)
tr[i + n] = arr[i];
for (int i = n - 1; i >= 1; i--)
pull(i);
}
void apply(int k, const F &f) {
tr[k] *= f;
if (k < n)
lz[k] += f;
}
void pull(int k) {
tr[k] = tr[k << 1] + tr[k << 1 | 1];
}
void push(int k) {
apply(k << 1, lz[k]);
apply(k << 1 | 1, lz[k]);
lz[k] = {};
}
void Set(int p, const S &x) {
p += n;
for (int i = h; i >= 1; i--) push(p >> i);
tr[p] = x;
for (int i = 1; i <= h; i++) pull(p >> i);
}
S Get(int p) {
p += n;
for (int i = h; i >= 1; i--) push(p >> i);
return tr[p];
}
void Update(int l, int r, const F &f) {
l += n, r += n;
for (int i = h; i >= 1; i--) {
if ((l & ((1 << i) - 1)) != 0) push(l >> i);
if ((r & ((1 << i) - 1)) != 0) push((r - 1) >> i);
}
{
int l_ = l, r_ = r;
while (l < r) {
if (l & 1) apply(l++, f);
if (r & 1) apply(--r, f);
l >>= 1;
r >>= 1;
}
l = l_;
r = r_;
}
for (int i = 1; i <= h; i++) {
if ((l & ((1 << i) - 1)) != 0) pull(l >> i);
if ((r & ((1 << i) - 1)) != 0) pull((r - 1) >> i);
}
}
S Query(int l, int r) {
l += n, r += n;
for (int i = h; i >= 1; i--) {
if ((l & ((1 << i) - 1)) != 0) push(l >> i);
if ((r & ((1 << i) - 1)) != 0) push((r - 1) >> i);
}
S sml{}, smr{};
while (l < r) {
if (l & 1)
sml = sml + tr[l++];
if (r & 1)
smr = tr[--r] + smr;
l >>= 1;
r >>= 1;
}
return sml + smr;
}
};
取模类 (ModInt)
using u32 = unsigned;
using i64 = long long; using u64 = unsigned long long;
template <class T> constexpr T power(T a, u64 b, T res = 1) {
for (; b != 0; b /= 2, a *= a) {
if (b & 1) {
res *= a;
}
}
return res;
}
template <u32 P> constexpr u32 mulMod(u32 a, u32 b) { return u64(a) * b % P; }
template <u64 P> constexpr u64 mulMod(u64 a, u64 b) {
u64 res = a * b - u64(1.L * a * b / P - 0.5L) * P;
res %= P;
return res;
}
constexpr i64 safeMod(i64 x, i64 m) {
x %= m;
if (x < 0) {
x += m;
}
return x;
}
constexpr std::pair<i64, i64> invGcd(i64 a, i64 b) {
a = safeMod(a, b);
if (a == 0) {
return {b, 0};
}
i64 s = b, t = a;
i64 m0 = 0, m1 = 1;
while (t) {
i64 u = s / t;
s -= t * u;
m0 -= m1 * u;
std::swap(s, t);
std::swap(m0, m1);
}
if (m0 < 0) {
m0 += b / s;
}
return {s, m0};
}
template <std::unsigned_integral U, U P> struct ModIntBase {
public:
constexpr ModIntBase() : x(0) {}
template <std::unsigned_integral T> constexpr ModIntBase(T x_) : x(x_ % mod()) {}
template <std::signed_integral T> constexpr ModIntBase(T x_) {
using S = std::make_signed_t<U>;
S v = x_ % S(mod());
if (v < 0) {
v += mod();
}
x = v;
}
constexpr static U mod() { return P; }
constexpr U val() const { return x; }
constexpr ModIntBase operator-() const {
ModIntBase res;
res.x = (x == 0 ? 0 : mod() - x);
return res;
}
constexpr ModIntBase inv() const { return power(*this, mod() - 2); }
constexpr ModIntBase &operator*=(const ModIntBase &rhs) & {
x = mulMod<mod()>(x, rhs.val());
return *this;
}
constexpr ModIntBase &operator+=(const ModIntBase &rhs) & {
x += rhs.val();
if (x >= mod()) {
x -= mod();
}
return *this;
}
constexpr ModIntBase &operator-=(const ModIntBase &rhs) & {
x -= rhs.val();
if (x >= mod()) {
x += mod();
}
return *this;
}
constexpr ModIntBase &operator/=(const ModIntBase &rhs) & { return *this *= rhs.inv(); }
friend constexpr ModIntBase operator*(ModIntBase lhs, const ModIntBase &rhs) {
lhs *= rhs;
return lhs;
}
friend constexpr ModIntBase operator+(ModIntBase lhs, const ModIntBase &rhs) {
lhs += rhs;
return lhs;
}
friend constexpr ModIntBase operator-(ModIntBase lhs, const ModIntBase &rhs) {
lhs -= rhs;
return lhs;
}
friend constexpr ModIntBase operator/(ModIntBase lhs, const ModIntBase &rhs) {
lhs /= rhs;
return lhs;
}
friend constexpr std::istream &operator>>(std::istream &is, ModIntBase &a) {
i64 i;
is >> i;
a = i;
return is;
}
friend constexpr std::ostream &operator<<(std::ostream &os, const ModIntBase &a) {
return os << a.val();
}
friend constexpr bool operator==(const ModIntBase &lhs, const ModIntBase &rhs) {
return lhs.val() == rhs.val();
}
friend constexpr std::strong_ordering operator<=>(const ModIntBase &lhs,
const ModIntBase &rhs) {
return lhs.val() <=> rhs.val();
}
private:
U x;
};
template <u32 P> using ModInt = ModIntBase<u32, P>;
template <u64 P> using ModInt64 = ModIntBase<u64, P>;
异或 Trie
struct XorTrie {
std::vector<std::array<int, 2>> ch;
int tot = 1;
XorTrie(int n) : ch(n * 32) {}
void insert(int x) {
for (int i = 30, u = 1; i >= 0; i--) {
int c = (x >> i) & 1;
if (not ch[u][c]) {
ch[u][c] = ++tot;
}
u = ch[u][c];
}
}
int query(int x) {
int res = 0;
for (int i = 30, u = 1; i >= 0; i--) {
int c = (x >> i) & 1;
if (ch[u][c ^ 1]) {
u = ch[u][c ^ 1];
res |= (1 << i);
} else {
u = ch[u][c];
}
}
return res;
}
};