XCPC模板
!!!声明:自用模板,使用前请自测,比赛中出现bug概不负责。
目录
一、杂项
__int128_t重载
using i128 = __int128_t;
std::ostream &operator<<(std::ostream &os, i128 n) {
if (n == 0) {
return os << 0;
}
std::string s;
while (n > 0) {
s += char('0' + n % 10);
n /= 10;
}
std::reverse(s.begin(), s.end());
return os << s;
}
二分整数
while (l < r) { // 左边界
int mid = l + r >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
while (l < r) { // 右边界
int mid = l + r + 1 >> 1;
if (check(mid)) {
l = mid;
} else {
r = mid - 1;
}
}
二分实数
using real = long double;
constexpr real eps = 1E-7;
while (r - l > std::max(1.0, l) * eps) {
double x = (l + r) / 2;
if (check(x)) {
r = x;
} else {
l = x;
}
}
DEBUG
template <class T, size_t size = std::tuple_size<T>::value> std::string to_debug(T, std::string s = "") requires(not std::ranges::range<T>);
std::string to_debug(auto x) requires requires(std::ostream& os) { os << x; } { return static_cast<std::ostringstream>(std::ostringstream() << x).str(); }
std::string to_debug(std::ranges::range auto x, std::string s = "") requires(not std::is_same_v<decltype(x), std::string>) {
for (auto xi : x) { s += ", " + to_debug(xi); }
return "[" + s.substr(s.empty() ? 0 : 2) + "]";
}
template <class T, size_t size> std::string to_debug(T x, std::string s) requires(not std::ranges::range<T>) {
[&]<size_t... I>(std::index_sequence<I...>) { ((s += ", " + to_debug(get<I>(x))), ...); }(std::make_index_sequence<size>());
return "(" + s.substr(s.empty() ? 0 : 2) + ")";
}
#define debug(...) std::cerr << __LINE__ << ": (" #__VA_ARGS__ ") = " << to_debug(std::tuple(__VA_ARGS__)) << "\n"
二、图
树链剖分(HLD)
点击展开
using Edge = int;
struct HLD { // 下标从1开始
int n, times = 0;
std::vector<int> siz, top, dep, fa, in, out, seq;
std::vector<std::vector<Edge>> adj;
HLD(const auto &adj, int root = 1) : n((int)adj.size() - 1), adj(adj) {
siz.resize(n + 1), top.resize(n + 1), dep.resize(n + 1), in.resize(n + 1), out.resize(n + 1), seq.resize(n + 1), fa.resize(n + 1);
dep[root] = 1, top[root] = root;
dfsSiz(root), dfsHld(root);
}
void dfsSiz(int u) {
if (fa[u] != 0) {
adj[u].erase(std::find(adj[u].begin(), adj[u].end(), fa[u]));
}
siz[u] = 1;
for (auto &v : adj[u]) {
fa[v] = u;
dep[v] = dep[u] + 1;
dfsSiz(v);
siz[u] += siz[v];
if (siz[v] > siz[adj[u][0]]) {
std::swap(v, adj[u][0]);
}
}
}
void dfsHld(int u) {
in[u] = ++times;
seq[in[u]] = u;
for (auto v : adj[u]) {
top[v] = v == adj[u][0] ? top[u] : v;
dfsHld(v);
}
out[u] = times;
}
int lca(int u, int v) {
while (top[u] != top[v]) {
dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
}
return dep[u] < dep[v] ? u : v;
}
int rootedLca(int a, int b, int c) { return lca(a, b) ^ lca(b, c) ^ lca(a, c); }
int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[(lca(u, v))]; }
bool inSubtree(int u, int v) { return in[v] <= in[u] && in[u] <= out[v]; }
int jump(int u, int k) {
if (dep[u] < k) return -1;
int d = dep[u] - k;
while (dep[top[u]] - d && u) u = fa[top[u]];
return seq[in[u] - dep[u] + d];
}
template<typename Q>
void modifyPath(int u, int v, const Q &q, bool edge = false) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
q(in[top[u]], in[u]);
u = fa[top[u]];
}
if (dep[u] > dep[v]) std::swap(u, v);
q(in[u] + edge, in[v]);
}
template<typename Q>
void modifySubtree(int u, const Q &q) { q(in[u], out[u]); }
template<typename T, typename Q>
T queryPath(int u, int v, const Q &q, bool edge = false) {
T ret = T();
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
ret = q(in[top[u]], in[u]) + ret;
u = fa[top[u]];
}
if (dep[u] > dep[v]) std::swap(u, v);
return q(in[u] + edge, in[v]) + ret;
}
template<typename T, typename Q>
T querySubtree(int u, const Q &q) { return q(in[u], out[u]); }
template<typename T, typename Q, typename F>
T queryPathNoncommutative(int u, int v, const Q &q, const F &f, bool edge = false) {
T left = T(), right = T();
while(top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) std::swap(u, v), std::swap(left, right);
left = q(in[top[u]], in[u]) + left;
u = fa[top[u]];
}
if (dep[u] > dep[v]) std::swap(u, v), std::swap(left, right);
return f(left, q(in[u] + edge, in[v]) + right);
}
template<typename T, typename Q>
T queryPathDirection(int u, int v, const Q &q, bool edge = false) {
T left = T(), right = T();
while(top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) {
right = q(in[top[v]], in[v]) + right;
v = fa[top[v]];
} else {
left = q(in[top[u]], in[u]) + left;
u = fa[top[u]];
}
}
if (dep[u] > dep[v]) {
left = q(in[v], in[u]) + left;
} else {
right = q(in[u], in[v]) + right;
}
std::swap(left.lmx, left.rmx);
return left + right;
}
std::pair<std::unordered_map<int, std::vector<int>>, int> virtualTree(std::vector<int> v) {
auto cmp = [&](int a, int b) { return in[a] < in[b]; };
std::sort(v.begin(), v.end(), cmp);
v.erase(std::unique(v.begin(), v.end()), v.end());
const int k = (int)size(v);
for (int i = 0; i + 1 < k; ++i) {
v.push_back(lca(v[i], v[i + 1]));
}
std::sort(v.begin(), v.end(), cmp);
v.erase(std::unique(v.begin(), v.end()), v.end());
std::unordered_map<int, std::vector<int>> res;
std::vector<int> stk;
for (auto x : v) {
while (!stk.empty() && out[stk.back()] < in[x]) {
stk.pop_back();
}
if (!stk.empty()) {
res[stk.back()].push_back(x);
}
stk.push_back(x);
}
return {res, v[0]};
}
std::pair<std::vector<int>, std::vector<std::pair<int, int>>> compress(std::vector<int> v) {
auto cmp = [&](int a, int b) { return in[a] < in[b]; };
std::sort(v.begin(), v.end(), cmp);
v.erase(std::unique(v.begin(), v.end()), v.end());
const int k = (int)size(v);
for (int i = 0; i + 1 < k; ++i) {
v.push_back(lca(v[i], v[i + 1]));
}
std::sort(v.begin(), v.end(), cmp);
v.erase(std::unique(v.begin(), v.end()), v.end());
std::vector<std::pair<int, int> > edges;
std::vector<int> stk;
for (auto x : v) {
while (!stk.empty() && out[stk.back()] < in[x]) {
stk.pop_back();
}
if (!stk.empty()) {
edges.push_back({stk.back(), x});
}
stk.push_back(x);
}
return {v, edges};
}
};
强联通分量(SCC)
点击展开
struct SCC {
int n;
std::vector<std::vector<int>> adj;
std::vector<int> stk;
std::vector<int> dfn, low, bel;
int cur, cnt;
SCC() {}
SCC(int n) { init(n); }
void init(int n) {
this->n = n;
adj.assign(n, {});
dfn.assign(n, -1), low.resize(n), bel.assign(n, -1);
stk.clear();
cur = cnt = 0;
}
void addEdge(int u, int v) { adj[u].push_back(v); }
void tarjan(int u) {
dfn[u] = low[u] = cur++;
stk.push_back(u);
for (auto v : adj[u]) {
if (dfn[v] == -1) {
tarjan(v);
low[u] = std::min(low[u], low[v]);
} else if (bel[v] == -1) {
low[u] = std::min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
int y;
do {
y = stk.back();
bel[y] = cnt;
stk.pop_back();
} while (y != u);
cnt += 1;
}
}
std::vector<int> work() {
for (int i = 0; i < n; ++i) {
if (dfn[i] == -1) {
tarjan(i);
}
}
return bel;
}
struct Graph {
int n;
std::vector<std::pair<int, int>> edges;
std::vector<int> siz;
std::vector<int> cnte;
};
Graph compress() {
Graph g;
g.n = cnt;
g.siz.resize(cnt);
g.cnte.resize(cnt);
for (int i = 0; i < n; ++i) {
g.siz[bel[i]]++;
for (auto j : adj[i]) {
if (bel[i] != bel[j]) {
g.edges.emplace_back(bel[i], bel[j]);
g.cnte[bel[j]]++;
}
}
}
return g;
}
};
边双联通分量(EDCC)
点击展开
struct EDCC {
int n, times = 0, top = 0, dcc_cnt = 0, idx = 0;
std::vector<std::vector<int>> adj, dcc;
std::vector<int> isb, dfn, low, stk, d, id, h, e, ne;
EDCC () {}
EDCC(int n, int m) : n(n), isb(m), dfn(n), low(n), stk(n + 10), id(n), h(n, -1), e(m), ne(m), d(n + 10), dcc(n + 10) {}
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
e[idx] = a, ne[idx] = h[b], h[b] = idx++;
}
void tarjan(int u, int from) {
dfn[u] = low[u] = ++ times;
stk[ ++ top] = u;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (!dfn[j]) {
tarjan(j, i);
low[u] = min(low[u], low[j]);
if (dfn[u] < low[j]) isb [i] = isb[i ^ 1] = true;
} else if (i != (from ^ 1)) low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u]) {
int y;
dcc_cnt ++ ;
do {
y = stk[top -- ];
id[y] = dcc_cnt;
dcc[dcc_cnt].push_back(y);
} while (y != u);
}
}
void build() {
tarjan(1, -1);
for (int i = 0; i < idx; ++ i)
if (isb[i]) d[id[e[i]]] ++ ;
}
};
点双联通分量(VDCC)
点击展开
struct VDCC {
int n, top = 0, times = 0, dcc_cnt = 0, root;
std::vector<std::vector<int>> adj, dcc;
std::vector<int> dfn, low, stk;
std::vector<bool> cut;
VDCC(int n) : n(n), adj(n), dcc(n + 10), dfn(n), low(n), stk(n + 10), cut(n) {}
void add(int a, int b) { adj[a].push_back(b), adj[b].push_back(a); }
void tarjan(int u) {
dfn[u] = low[u] = ++times;
stk[ ++ top] = u;
if (u == root && adj[u].size() == 0) return void(dcc[ ++ dcc_cnt].push_back(u)); // 如果u是孤点
int cnt = 0;
for (auto j : adj[u])
if (!dfn[j]) {
tarjan(j);
low[u] = min(low[u], low[j]);
if (dfn[u] <= low[j]) {
int y;
++ dcc_cnt, ++ cnt;
if (u != root || cnt > 1) cut[u] = true; // 判断是否为割点, 如果u是根节点则至少需要两条边
do {
y = stk[top -- ];
dcc[dcc_cnt].push_back(y);
} while (y != j);
dcc[dcc_cnt].push_back(u);
}
} else low[u] = min(low[u], dfn[j]);
}
void build() {
for (root = 0; root < n; ++ root)
if (!dfn[root]) tarjan(root);
}
};
三、数据结构
并查集(DSU)
struct DSU {
std::vector<int> p, siz;
DSU(int n) { init(n); }
void init(int n) {
p.resize(n);
std::iota(p.begin(), p.end(), 0);
siz.assign(n, 1);
}
int leader(int x) {
while (x != p[x]) x = p[x] = p[p[x]];
return x;
}
bool same(int x, int y) { return leader(x) == leader(y); }
bool merge(int x, int y) {
x = leader(x), y = leader(y);
if (x == y) return false;
siz[x] += siz[y], p[y] = x;
return true;
}
int size(int x) { return siz[leader(x)]; }
};
可撤销并查集(DSU with Rollback)
struct DSU {
std::vector<int> p, siz;
std::vector<std::array<int, 2>> his;
DSU(int n) { init(n); }
void init(int n) {
p.resize(n);
std::iota(p.begin(), p.end(), 0);
siz.assign(n, 1);
}
int leader(int x) {
while (x != p[x]) x = p[x] = p[p[x]];
return x;
}
bool same(int x, int y) { return leader(x) == leader(y); }
bool merge(int x, int y) {
x = leader(x), y = leader(y);
if (x == y) return false;
his.push_back({x, y});
siz[x] += siz[y], p[y] = x;
return true;
}
int time() { return size(his;) }
int size(int x) { return siz[leader(x)]; }
void revert(int tm) {
while (size(his) > tm) {
auto [x, y] = his.back();
his.pop_back();
f[y] = y;
siz[x] -= siz[y];
}
}
};
树状数组(Fenwick)
template<typename T>
struct Fenwick {
const int n;
std::vector<T> tr;
Fenwick(int n) : n(n), tr(n + 1) {}
void add(int x, T c) {
for (int i = x; i <= n; i += i & -i) tr[i] += c;
}
void add(int l, int r, T c) {
add(l, c);
if (r + 1 <= n) add(r + 1, -c);
}
T get(int x) {
T res = T();
for (int i = x; i > 0; i -= i & -i) res += tr[i];
return res;
}
T get(int l, int r) {
return get(r) - get(l - 1);
}
int find_first(T sum) {
int ans = 0; T val = 0;
for (int i = std::__lg(n); i >= 0; --i) {
if ((ans | (1 << i)) <= n and val + tr[ans | (1 << i)] < sum) {
ans |= 1 << i;
val += tr[ans];
}
}
return ans + 1;
}
int find_last(T sum) {
int ans = 0; T val = 0;
for (int i = std::__lg(n); i >= 0; --i) {
if ((ans | (1 << i)) <= n and val + tr[ans | (1 << i)] <= sum) {
ans |= 1 << i;
val += tr[ans];
}
}
return ans;
}
};
using BIT = Fenwick<int>;
单点修改线段树(SegTree)
点击展开
template<class Info>
struct SegTree { // 下标从1开始
const int n;
std::vector<Info> tr;
SegTree(int n) : n(n), tr(4 << (std::__lg(n))) {}
SegTree(int n, const std::vector<Info> &a) : SegTree(n) {
std::function<void(int, int, int)> build = [&](int u, int l, int r) {
if (l == r) return void(tr[u] = a[r]);
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
};
build(1, 1, n);
}
void pushup(int u) { tr[u] = tr[u << 1] + tr[u << 1 | 1]; }
void modify(int u, int l, int r, int x, const Info &v) {
if (l == r) return void(tr[u] = v);
int mid = l + r >> 1;
if (x <= mid) modify(u << 1, l, mid, x, v);
else modify(u << 1 | 1, mid + 1, r, x, v);
pushup(u);
}
Info query(int u, int l, int r, int ql, int qr) {
if (l > qr || r < ql) return Info();
if (ql <= l && r <= qr) return tr[u];
int mid = l + r >> 1;
return query(u << 1, l, mid, ql, qr) + query(u << 1 | 1, mid + 1, r, ql, qr);
}
void modify(int x, const Info &v) { modify(1, 1, n, x, v); }
Info query(int l, int r) { return query(1, 1, n, l, r);}
};
struct Info {};
Info operator+(const Info &l, const Info &r) {
return {};
}
懒标记线段树(LazySegTree)
点击展开
template<class Info, class Tag>
struct LazySegTree { // 下标从1开始
const int n;
std::vector<Tag> tag;
std::vector<Info> tr;
LazySegTree(int n) : n(n), tr(4 << std::__lg(n)), tag(4 << std::__lg(n)) {}
LazySegTree(const std::vector<Info> &a) : LazySegTree((int)a.size()) {
std::function<void(int, int, int)> build = [&](int u, int l, int r) {
if (l == r) return void(tr[u] = a[r - 1]);
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
};
build(1, 1, n);
}
void pushup(int u) { tr[u] = tr[u << 1] + tr[u << 1 | 1]; }
void apply(int u, const Tag &v) { tr[u].apply(v), tag[u].apply(v); }
void pushdown(int u) {
apply(u << 1, tag[u]), apply(u << 1 | 1, tag[u]);
tag[u] = Tag();
}
void modify(int u, int l, int r, int x, const Info &v) {
if (l == r) return void(tr[u] = v);
int mid = l + r >> 1;
if (x <= mid) modify(u << 1, l, mid, x, v);
else modify(u << 1 | 1, mid + 1, r, x, v);
pushup(u);
}
void modify(int x, const Info &v) { modify(1, 1, n, x, v); }
Info query(int u, int l, int r, int ql, int qr) {
if (l > qr || r < ql) return Info();
if (ql <= l && r <= qr) return tr[u];
int mid = l + r >> 1;
pushdown(u);
return query(u << 1, l, mid, ql, qr) + query(u << 1 | 1, mid + 1, r, ql, qr);
}
Info query(int l, int r) { return query(1, 1, n, l, r);}
void rangeApply(int u, int l, int r, int ql, int qr, const Tag &v) {
if (l > qr || r < ql) return ;
if (l >= ql && r <= qr) { return void(apply(u, v)); }
int mid = l + r >> 1;
pushdown(u);
rangeApply(u << 1, l, mid, ql, qr, v), rangeApply(u << 1 | 1, mid + 1, r, ql, qr, v);
pushup(u);
}
void rangeApply(int l, int r, const Tag &v) { return rangeApply(1, 1, n, l, r, v); }
};
struct Tag {
void apply(const Tag &t) {}
};
struct Info {
int n;
void apply(const Tag &t) {}
};
Info operator+(const Info &l, const Info &r) {
return {};
}
状压RMQ
点击展开
template<class T,
class Cmp = std::less<T>>
struct RMQ {
const Cmp cmp = Cmp();
static constexpr unsigned B = 64;
using u64 = unsigned long long;
int n;
std::vector<std::vector<T>> a;
std::vector<T> pre, suf, ini;
std::vector<u64> stk;
RMQ() {}
RMQ(const std::vector<T> &v) {
init(v);
}
void init(const std::vector<T> &v) {
n = v.size();
pre = suf = ini = v;
stk.resize(n);
if (!n) return;
const int M = (n - 1) / B + 1;
const int lg = std::__lg(M);
a.assign(lg + 1, std::vector<T>(M));
for (int i = 0; i < M; ++i) {
a[0][i] = v[i * B];
for (int j = 1; j < B && i * B + j < n; ++j) {
a[0][i] = std::min(a[0][i], v[i * B + j], cmp);
}
}
for (int i = 1; i < n; ++i) {
if (i % B) {
pre[i] = std::min(pre[i], pre[i - 1], cmp);
}
}
for (int i = n - 2; i >= 0; --i) {
if (i % B != B - 1) {
suf[i] = std::min(suf[i], suf[i + 1], cmp);
}
}
for (int j = 0; j < lg; ++j) {
for (int i = 0; i + (2 << j) <= M; ++i) {
a[j + 1][i] = std::min(a[j][i], a[j][i + (1 << j)], cmp);
}
}
for (int i = 0; i < M; ++i) {
const int l = i * B;
const int r = std::min(1U * n, l + B);
u64 s = 0;
for (int j = l; j < r; ++j) {
while (s && cmp(v[j], v[std::__lg(s) + l])) {
s ^= 1ULL << std::__lg(s);
}
s |= 1ULL << (j - l);
stk[j] = s;
}
}
}
T operator()(int l, int r) { // [l, r)
if (l / B != (r - 1) / B) {
T ans = std::min(suf[l], pre[r - 1], cmp);
l = l / B + 1;
r = r / B;
if (l < r) {
int k = std::__lg(r - l);
ans = std::min({ans, a[k][l], a[k][r - (1 << k)]}, cmp);
}
return ans;
} else {
int x = B * (l / B);
return ini[__builtin_ctzll(stk[r - 1] >> (l - x)) + l];
}
}
};
ST表
struct ST {
std::vector<std::vector<int>> f, g, h;
ST(int n, std::vector<int>& a) : f(n, std::vector<int>(std::__lg(n) + 1)),
g(n, std::vector<int>(std::__lg(n) + 1)), h(n, std::vector<int>(std::__lg(n) + 1)) {
for (int i = 1; i < n; i ++) {
f[i][0] = g[i][0] = h[i][0] = a[i];
}
for (int j = 1; (1LL << j) < n; j ++) {
for (int i = 1; i + (1LL << j) - 1 < n; i ++) {
f[i][j] = std::max(f[i][j - 1], f[i + (1LL << (j - 1))][j - 1]);
g[i][j] = std::min(g[i][j - 1], g[i + (1LL << (j - 1))][j - 1]);
h[i][j] = std::__gcd(h[i][j - 1], h[i + (1LL << (j - 1))][j - 1]);
}
}
}
int askMax(int l, int r) {
int k = std::__lg(r - l + 1);
return std::max(f[l][k], f[r - (1LL << k) + 1][k]);
}
int askMin(int l, int r) {
int k = std::__lg(r - l + 1);
return std::min(g[l][k], g[r - (1LL << k) + 1][k]);
}
int askGcd(int l, int r) {
int k = std::__lg(r - l + 1);
return std::__gcd(h[l][k], h[r - (1LL << k) + 1][k]);
}
};
高精度整数-不含负数(BigInt)
点击展开
struct BigInt {
std::vector<char> v;
BigInt(int x = 0) : v{} {
do v.push_back(x % 10); while (x /= 10);
}
BigInt(std::string &x) : v{} {
assert(size(x) != 0);
for (int i = (int)size(x) - 1; i >= 0; --i) {
v.push_back(x[i] - '0');
}
}
BigInt &operator=(int x) {
v.clear();
do v.push_back(x % 10); while (x /= 10);
return *this;
}
BigInt &operator=(const BigInt &x) {
v.resize(x.v.size());
memcpy(const_cast<char *>(v.data()), x.v.data(), x.v.size() * sizeof(char));
return *this;
}
friend bool operator==(const BigInt &a, const BigInt &b) {
if (size(a.v) == size(b.v)) {
int idx = 0;
while (idx < (int)size(a.v) && a.v[idx] == b.v[idx]) idx++;
return idx < (int)size(a.v);
} else {
return false;
}
}
friend bool operator!=(const BigInt &a, const BigInt &b) {
return !(a == b);
}
friend bool operator<(const BigInt &a, const BigInt &b) {
if (size(a.v) == size(b.v)) {
int idx = size(a.v) - 1;
while (idx >= 0 && a.v[idx] == b.v[idx]) idx--;
return idx >= 0 && a.v[idx] < b.v[idx];
}
return size(a.v) < size(b.v);
}
friend bool operator<=(const BigInt &a, const BigInt &b) {
if (size(a.v) == size(b.v)) {
int idx = size(a.v) - 1;
while (idx >= 0 && a.v[idx] == b.v[idx]) idx--;
return idx == -1 || a.v[idx] <= b.v[idx];
}
return size(a.v) < size(b.v);
}
friend bool operator>(const BigInt &a, const BigInt &b) {
if (size(a.v) == size(b.v)) {
int idx = size(a.v) - 1;
while (idx >= 0 && a.v[idx] == b.v[idx]) idx--;
return idx >= 0 && a.v[idx] > b.v[idx];
}
return size(a.v) > size(b.v);
}
friend bool operator>=(const BigInt &a, const BigInt &b) {
if (size(a.v) == size(b.v)) {
int idx = size(a.v);
while (idx >= 0 && a.v[idx] == b.v[idx]) idx--;
return idx == -1 || a.v[idx] >= b.v[idx];
}
return size(a.v) > size(b.v);
}
BigInt &operator+=(const BigInt &x) & {
int n = std::max<int>(size(v), size(x.v)), tmp = 0;
bool flag = false;
for (int i = 0; i < n; ++i) {
if (i >= (int)size(v)) v.push_back(0);
if (i < (int)size(x.v)) v[i] += x.v[i];
if (flag) v[i] += 1, flag = false;
if (v[i] >= 10) v[i] %= 10, flag = true;
}
if (flag) v.push_back(1);
return *this;
}
BigInt &operator-=(const BigInt &x) & {
assert(*this >= x);
bool flag = false;
for (int i = 0; i < (int)size(v); ++i) {
if (i < (int)size(x.v)) v[i] -= x.v[i];
if (flag) v[i] -= 1, flag = false;
if (v[i] < 0) v[i] += 10, flag = true;
}
while (size(v) > 1 && v.back() == 0) v.pop_back();
return *this;
}
BigInt &operator*=(const int &x) & {
int tmp = 0;
for (int i = 0; i < size(v); ++i) {
tmp += (int)x * v[i];
v[i] = tmp % 10;
tmp /= 10;
}
while (tmp) {
v.push_back(tmp % 10);
tmp /= 10;
}
return *this;
}
BigInt &operator*=(const BigInt &x) & {
BigInt result;
result.v.resize(size(v) + size(x.v));
for (int i = 0; i < (int)size(v); ++i) {
for (int j = 0; j < (int)size(x.v); ++j) {
result.v[i + j] += v[i] * x.v[j];
result.v[i + j + 1] += result.v[i + j] / 10;
result.v[i + j] %= 10;
}
}
while (size(result.v) > 1 && result.v.back() == 0) result.v.pop_back();
return *this = result;
}
BigInt &operator/=(const int &x) & {
int r = 0;
for (int i = size(v) - 1; i >= 0; --i) {
r = r * 10 + v[i];
v[i] = r / x;
r %= x;
}
while (size(v) > 1 && v.back() == 0) v.pop_back();
return *this;
}
int operator%=(const int &x) {
int r = 0;
for (int i = size(v) - 1; i >= 0; --i) {
r = r * 10 + v[i];
r %= x;
}
return r;
}
friend BigInt operator+(BigInt a, const BigInt &b) {
return a += b;
}
friend BigInt operator-(BigInt a, const BigInt &b) {
return a -= b;
}
friend BigInt operator*(BigInt a, const int &b) {
return a *= b;
}
friend BigInt operator*(BigInt a, const BigInt &b) {
return a *= b;
}
friend BigInt operator/(BigInt a, const int &b) {
return a /= b;
}
friend int operator%(BigInt a, const int &b) {
return a %= b;
}
friend std::istream &operator>>(std::istream &is, BigInt &a) {
std::string str;
is >> str;
a = BigInt(str);
return is;
}
friend std::ostream &operator<<(std::ostream &os, const BigInt &a) {
for (int i = a.v.size() - 1; i >= 0; --i) os << (char)(a.v[i] + '0');
return os;
}
};
四、数学,几何
快速幂(power)
int power(int a, int b, int p) {
int c = 1;
while (b) [
if (b & 1) {
c = 1LL * c * a % p;
}
a = 1LL * a * a % p;
b >>= 1;
]
return c;
}
欧拉筛
std::vector<int> primes, least;
void sieve(int n) {
std::vector<int> nums;
least.assign(n + 1, 0);
for (int i = 2; i <= n; ++i) {
if (least[i] == 0) {
least[i] = i;
nums.push_back(i);
}
for (auto p : primes) {
if (i * p > n) {
break;
}
least[i * p] = p;
if (p == least[i]) {
break;
}
}
}
primes = nums;
}
bool isprime(int n) {
return least[n] == n;
}
筛欧拉函数
std::vector<int> primes, phi, least;
void sieve(int n) {
least.assign(n + 1, 0);
phi.assign(n + 1, 0);
primes.clear();
for (int i = 2; i <= n; ++i) {
if (least[i] == 0) {
least[i] = i;
phi[i] = i - 1;
primes.push_back(i);
}
for (auto p : primes) {
if (i * p > n) {
break;
}
least[i * p] = p;
if (p == least[i]) {
phi[i * p] = phi[i] * p;
break;
}
phi[i * p] = phi[i] * (p - 1);
}
}
for (int i = 2; i <= n; ++i) {
phi[i] += phi[i - 1];
}
}
扩展欧几里得(exgcd)
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1, y = 0;
return a;
}
int g = exgcd(b, a % b, y, x);
y -= a / b * x;
return g;
}
// ax + b = 0 (mod m)
std::pair<int, int> sol(int a, int b, int m) {
assert(m > 0);
b *= -1;
int x, y;
int g = exgcd(a, m, x, y);
if (g < 0) {
g *= -1;
x *= -1;
y *= -1;
}
if (b % g != 0) {
return {-1, -1};
}
x = x * (b / g) % (m / g);
if (x < 0) {
x += m / g;
}
return {x, m / g};
}
std::array<int, 3> exgcd(int a, int b) {
if (!b) {
return {a, 1, 0};
}
auto [g, x, y] = exgcd(b, a % b);
return {g, y, x - a / b * y};
}
素性测试(Factorizer)
点击展开
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
namespace Factorizer {
std::vector<int> primes;
std::vector<int> least;
void sieve(int n) {
std::vector<int> nums;
least.assign(n + 1, 0);
for (int i = 2; i <= n; ++i) {
if (least[i] == 0) {
least[i] = i;
nums.push_back(i);
}
for (auto p : nums) {
if (i * p > n) {
break;
}
least[i * p] = p;
if (p == least[i]) {
break;
}
}
}
primes = nums;
}
constexpr bool miller_rabin(long long n) {
if (n <= 1 || (n != 2 && n % 2 == 0)) return false;
for (auto a : {3, 5, 7, 11, 13, 17, 19, 23, 29}) {
if (n % a == 0) return n == a;
}
if (n < 31 * 31) return true;
long long d = n - 1;
while (d % 2 == 0) d /= 2;
constexpr long long bases[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37
};
for (long long a : bases) {
if (n == a) return true;
long long t = d;
long long y = 1 % n;
for (long long _t = t; _t != 0; _t >>= 1) {
if (_t & 1) y = (__int128) y * a % n;
a = (__int128) a * a % n;
}
while (t != n - 1 && y != 1 && y != n - 1) {
y = (__int128) y * y % n;
t <<= 1;
}
if (y != n - 1 && t % 2 == 0) return false;
}
return true;
}
long long pollard_rho(long long n) {
if (n == 1 || miller_rabin(n)) return n;
long long now = 0;
do {
long long t = std::gcd(++now, n), r = t;
if (t != 1 && t != n) return t;
long long g = 1;
do {
t = ((__int128) t * t % n + now) % n;
r = ((__int128) r * r % n + now) % n;
r = ((__int128) r * r % n + now) % n;
} while ((g = std::gcd(abs(t - r), n)) == 1);
if (g != n) return g;
} while (now < n / now);
return 0;
}
std::vector<long long> factor(long long n) {
if (n == 1) return {};
std::vector<long long> g, d;
d.push_back(n);
while (!d.empty()) {
auto v = d.back();
d.pop_back();
auto rho = pollard_rho(v);
if (rho == v) {
g.push_back(rho);
} else {
d.push_back(rho);
d.push_back(v / rho);
}
}
std::sort(g.begin(), g.end());
return g;
}
}
取模类(Mint)
点击展开
using i64 = long long;
template <class T>
constexpr T power(T a, i64 b) {
T res = 1;
for (; b; b /= 2, a *= a)
if (b % 2) res *= a;
return res;
}
template <int P>
struct MInt {
int x;
constexpr MInt() : x{} {}
constexpr MInt(i64 x) : x{norm(x % P)} {}
constexpr int norm(int x) const {
if (x < 0) x += P;
if (x >= P) x -= P;
return x;
}
constexpr int val() const { return x; }
explicit constexpr operator int() const { return x; }
constexpr MInt operator-() const {
MInt res;
res.x = norm(P - x);
return res;
}
constexpr MInt inv() const {
assert(x != 0);
return power(*this, P - 2);
}
constexpr MInt &operator*=(MInt rhs) {
x = 1ll * x * rhs.x % P;
return *this;
}
constexpr MInt &operator+=(MInt rhs) {
x = norm(x + rhs.x);
return *this;
}
constexpr MInt &operator-=(MInt rhs) {
x = norm(x - rhs.x);
return *this;
}
constexpr MInt &operator/=(MInt rhs) { return *this *= rhs.inv(); }
friend constexpr MInt operator*(MInt lhs, MInt rhs) {
MInt res = lhs;
res *= rhs;
return res;
}
friend constexpr MInt operator+(MInt lhs, MInt rhs) {
MInt res = lhs;
res += rhs;
return res;
}
friend constexpr MInt operator-(MInt lhs, MInt rhs) {
MInt res = lhs;
res -= rhs;
return res;
}
friend constexpr MInt operator/(MInt lhs, MInt rhs) {
MInt res = lhs;
res /= rhs;
return res;
}
friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {
i64 v;
is >> v;
a = MInt(v);
return is;
}
friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) { return os << a.val(); }
friend constexpr bool operator==(MInt lhs, MInt rhs) { return lhs.val() == rhs.val(); }
friend constexpr bool operator!=(MInt lhs, MInt rhs) { return lhs.val() != rhs.val(); }
};
template <int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();
constexpr int P = 998244353;
//constexpr int P = 1e9 + 7;
using Z = MInt<P>;
组合数(Comb,取模Z)
点击展开
struct Comb {
int n;
std::vector<Z> _fac, _invfac, _inv;
Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}
Comb(int n) : Comb() { init(n); }
void init(int m) {
if (m <= n) return;
_fac.resize(m + 1), _invfac.resize(m + 1), _inv.resize(m + 1);
for (int i = n + 1; i <= m; ++i) _fac[i] = _fac[i - 1] * i;
_invfac[m] = _fac[m].inv();
for (int i = m; i > n; --i) _invfac[i - 1] = _invfac[i] * i, _inv[i] = _invfac[i] * _fac[i - 1];
n = m;
}
Z fac(int m) {
if (m > n) init(2 * m);
return _fac[m];
}
Z invfac(int m) {
if (m > n) init(2 * m);
return _invfac[m];
}
Z inv(int m) {
if (m > n) init(2 * m);
return _inv[m];
}
Z binom(int n, int m) {
if (n < m || m < 0) return 0;
return fac(n) * invfac(m) * invfac(n - m);
}
} comb;
组合数(无Z)
constexpr int P = 1e9 + 7;
constexpr int L = 1e6 + 10;
int fac[L + 1], invfac[L + 1];
int binom(int n, int m) {
if (n < m || m < 0) {
return 0;
}
return 1LL * fac[n] * invfac[m] % P * invfac[n - m] % P;
}
int power(int a, int b) {
int c = 1;
while (b) {
if (b & 1) {
c = 1LL * c * a % P;
}
a = 1LL * a * a % P;
b >>= 1;
}
return c;
}
void combInit() {
fac[0] = 1;
for (int i = 1; i <= L; ++i) {
fac[i] = 1LL * fac[i - 1] * i % P;
}
invfac[L] = power(fac[L], P - 2);
for (int i = L; i; --i) {
invfac[i - 1] = 1LL * invfac[i] * i % P;
}
}
平面几何
点击展开
template<class T>
struct Point {
T x, y;
Point (const T &x_ = 0, const T &y_ = 0) : x(x_), y(y_) {}
template<class U>
operator Point<U>() {
return Point<U>(U(x), U(y));
}
Point &operator+=(const Point &p) & {
x += p.x, y += p.y;
return *this;
}
Point &operator-=(const Point &p) & {
x -= p.x, y -= p.y;
return *this;
}
Point &operator*=(const T &v) & {
x *= v, y *= v;
return *this;
}
Point &operator/=(const T &v) & {
x /= v, y /= v;
return *this;
}
Point &operator-() const {
return Point(-x, -y);
}
friend Point operator+(Point a, const Point &b) {
return a += b;
}
friend Point operator-(Point a, const Point &b) {
return a -= b;
}
friend Point operator*(Point a, const T &b) {
return a *= b;
}
friend Point operator/(Point a, const T &b) {
return a /= b;
}
friend Point operator*(const T &a, Point b) {
return b *= a;
}
friend bool operator==(const Point &a, const Point &b) {
return a.x == b.x && a.y == b.y;
}
friend std::istream &operator>>(std::istream &is, Point &p) {
return is >> p.x >> p.y;
}
friend std::ostream &operator<<(std::ostream &os, const Point &p) {
return os << "(" << p.x << ", " << p.y << ")";
}
};
template<class T>
struct Line {
Point<T> a;
Point<T> b;
Line(const Point<T> &a_ = Point<T>(), const Point<T> &b_ = Point<T>()) : a(a_), b(b_) {}
};
template<class T>
T dot(const Point<T> &a, const Point<T> &b) {
return a.x * b.x + a.y * b.y;
}
template<class T>
T cross(const Point<T> &a, const Point<T> &b) {
return a.x * b.y - a.y * b.x;
}
template<class T>
T square(const Point<T> &p) {
return dot(p, p);
}
template<class T>
double length(const Point<T> &p) {
return std::sqrt(square(p));
}
template<class T>
double length(const Line<T> &l) {
return length(l.a - l.b);
}
template<class T>
Point<T> normalize(const Point<T> &p) {
return p / length(p);
}
template<class T>
bool parallel(const Line<T> &l1, const Line<T> &l2) {
return cross(l1.b - l1.a, l2.b - l2.a) == 0;
}
template<class T>
double distance(const Point<T> &a, const Point<T> &b) {
return length(a - b);
}
template<class T>
double distancePL(const Point<T> &p, const Line<T> &l) {
return std::abs(cross(l.a - l.b, l.a - p)) / length(l);
}
template<class T>
double distancePS(const Point<T> &p, const Line<T> &l) {
if (dot(p - l.a, l.b - l.a) < 0) {
return distance(p, l.a);
}
if (dot(p - l.b, l.a - l.b) < 0) {
return distance(p, l.b);
}
return distancePL(p, l);
}
template<class T>
Point<T> rotate(const Point<T> &a) {
return Point(-a.y, a.x);
}
template<class T>
int sgn(const Point<T> &a) {
return a.y > 0 || (a.y == 0 && a.x > 0) ? 1 : -1;
}
template<class T>
bool pointOnLineLeft(const Point<T> &p, const Line<T> &l) {
return corss(l.b - l.a, p - l.a) > 0;
}
template<class T>
Point<T> lineIntersection(const Line<T> &l1, const Line<T> &l2) {
return l1.a + (l1.b - l1.a) * (cross(l2.b - l2.a, l1.a - l2.a) / cross(l2.b - l2.a, l1.a - l1.b));
}
template<class T>
bool pointOnSegment(const Point<T> &p, const Line<T> &l) {
return cross(p - l.a, l.b - l.a) == 0
&& std::min(l.a.x, l.b.x) <= p.x && p.x <= std::max(l.a.x, l.b.x)
&& std::min(l.a.y, l.b.y) <= p.y && p.y <= std::max(l.a.y, l.b.y);
}
template<class T>
bool pointInPolygon(const Point<T> &a, const std::vector<Point<T>> &p) {
int n = size(p);
for (int i = 0; i < n; ++i) {
if (pointOnSegment(a, Line(p[i], p[(i + 1) % n]))) {
return true;
}
}
int t = 0;
for (int i = 0; i < n; ++i) {
auto u = p[i];
auto v = p[(i + 1) % n];
if (u.x < a.x && v.x >= a.x && pointOnLineLeft(a, Line(v, u))) {
t ^= 1;
}
if (u.x >= a.x && v.x < a.x && pointOnLineLeft(a, Line(u, v))) {
t ^= 1;
}
}
return t == 1;
}
/**
* 0: 不相交
* 1: 严格相交
* 2: 重合
* 3: 在端点处相交
*/
template<class T>
std::tuple<int, Point<T>, Point<T>> segmentIntersection(const Line<T> &l1, const Line<T> &l2) {
if (std::max(l1.a.x, l1.b.x) < std::min(l2.a.x, l2.b.x)
|| std::min(l1.a.x, l1.b.x) > std::max(l2.a.x, l2.b.x)
|| std::max(l1.a.y, l1.b.y) < std::min(l2.a.y, l2.b.y)
|| std::min(l1.a.y, l1.b.y) > std::max(l2.a.y, l2.b.y)) {
return {0, Point<T>(), Point<T>()};
}
if (cross(l1.b - l1.a, l2.b - l2.a) == 0) {
if (cross(l1.b - l1.a, l2.a - l1.a) != 0) {
return {0, Point<T>(), Point<T>()};
} else {
auto maxx1 = std::max(l1.a.x, l1.b.x);
auto minx1 = std::min(l1.a.x, l1.b.x);
auto maxy1 = std::max(l1.a.y, l1.b.y);
auto miny1 = std::min(l1.a.y, l1.b.y);
auto maxx2 = std::max(l2.a.x, l2.b.x);
auto minx2 = std::min(l2.a.x, l2.b.x);
auto maxy2 = std::max(l2.a.y, l2.b.y);
auto miny2 = std::min(l2.a.y, l2.b.y);
Point<T> p1(std::max(minx1, minx2), std::max(miny1, miny2));
Point<T> p2(std::min(maxx1, maxx2), std::min(maxy1, maxy2));
if (!pointOnSegment(p1, l1)) {
std::swap(p1.y, p2.y);
}
if (p1 == p2) {
return {3, p1, p2};
} else {
return {2, p1, p2};
}
}
}
auto cp1 = cross(l2.a - l1.a, l2.b - l1.a);
auto cp2 = cross(l2.a - l1.b, l2.b - l1.b);
auto cp3 = cross(l1.a - l2.a, l1.b - l2.a);
auto cp4 = cross(l1.a - l2.b, l1.b - l2.b);
if ((cp1 > 0 && cp2 > 0) || (cp1 < 0 && cp2 < 0) || (cp3 > 0 && cp4 > 0) || (cp3 < 0 && cp4 < 0)) {
return {0, Point<T>(), Point<T>()};
}
Point p = lineIntersection(l1, l2);
if (cp1 != 0 && cp2 != 0 && cp3 != 0 && cp4 != 0) {
return {1, p, p};
} else {
return {3, p, p};
}
}
template<class T>
double distanceSS(const Line<T> &l1, const Line<T> &l2) {
if (std::get<0>(segmentIntersection(l1, l2)) != 0) {
return 0.0;
}
return std::min({distancePS(l1.a, l2), distancePS(l1.b, l2), distancePS(l2.a, l1), distance(l2.b, l1)});
}
template<class T>
bool segmentInPolygon(const Line<T> &l, const std::vector<Point<T>> &p) {
int n = size(p);
if (!pointInPolygon(l.a, p) || !pointInPolygon(l.b, p)) {
return false;
}
for (int i = 0; i < n; ++i) {
auto u = p[i];
auto v = p[(i + 1) % n];
auto w = p[(i + 2) % n];
auto [t, p1, p2] = segmentIntersection(l, Line(u, v));
if (t == 1) {
return false;
}
if (t == 0) {
continue;
}
if (t == 2) {
if (pointOnSegment(v, l) && v != l.a && v != l.b) {
if (cross(v - u, w - v) > 0) {
return false;
}
}
} else {
if (p1 != u && p1 != v) {
if (pointOnLineLeft(l.a, Line(v, u))
|| pointOnLineLeft(l.b, Line(v, u))) {
return false;
}
} else if (p1 == v) {
if (l.a == v) {
if (pointOnLineLeft(u, l)) {
if (pointOnLineLeft(w, l)
&& pointOnLineLeft(w, Line(u, v))) {
return false;
}
} else {
if (pointOnLineLeft(w, l)
|| pointOnLineLeft(w, Line(u, v))) {
return false;
}
}
} else if (l.b == v) {
if (pointOnLineLeft(u, Line(l.b, l.a))) {
if (pointOnLineLeft(w, Line(l.b, l.a))
&& pointOnLineLeft(w, Line(u, v))) {
return false;
}
} else {
if (pointOnLineLeft(w, Line(l.b, l.a))
|| pointOnLineLeft(w, Line(u, v))) {
return false;
}
}
} else {
if (pointOnLineLeft(u, l)) {
if (pointOnLineLeft(w, Line(l.b, l.a))
|| pointOnLineLeft(w, Line(u, v))) {
return false;
}
} else {
if (pointOnLineLeft(w, l)
|| pointOnLineLeft(w, Line(u, v))) {
return false;
}
}
}
}
}
}
return true;
}
template<class T>
std::vector<Point<T>> hp(std::vector<Line<T>> lines) {
std::sort(lines.begin(), lines.end(),
[&](auto l1, auto l2) {
auto d1 = l1.b - l1.a;
auto d2 = l2.b - l2.a;
if (sgn(d1) != sgn(d2)) {
return sgn(d1) == 1;
}
return cross(d1, d2) > 0;
});
std::deque<Line<T>> ls;
std::deque<Point<T>> ps;
for (auto l : lines) {
if (ls.empty()) {
ls.push_back(l);
continue;
}
while (!ps.empty() && !pointOnLineLeft(ps.back(), l)) {
ps.pop_back();
ls.pop_back();
}
while (!ps.empty() && !pointOnLineLeft(ps[0], l)) {
ps.pop_front();
ls.pop_front();
}
if (cross(l.b - l.a, ls.back().b - ls.back().a) == 0) {
if (dot(l.b - l.a, ls.back().b - ls.back().a) > 0) {
if (!pointOnLineLeft(ls.back().a, l)) {
assert(ls.size() == 1);
ls[0] = l;
}
continue;
}
return {};
}
ps.push_back(lineIntersection(ls.back(), l));
ls.push_back(l);
}
while (!ps.empty() && !pointOnLineLeft(ps.back(), ls[0])) {
ps.pop_back();
ls.pop_back();
}
if (ls.size() <= 2) {
return {};
}
ps.push_back(lineIntersection(ls[0], ls.back()));
return std::vector(ps.begin(), ps.end());
}
template<class T>
auto getHull(std::vector<Point<T>> p) {
std::sort(p.begin(), p.end(),
[&](auto a, auto b) {
return a.x < b.x || (a.x == b.x && a.y < b.y);
});
std::vector<Point<T>> hi, lo;
for (auto p : p) {
while (size(hi) > 1 && cross(hi.back() - hi.rbegin()[1], p - hi.back()) >= 0) {
hi.pop_back();
}
while (size(hi) && hi.back().x == p.x) {
hi.pop_back();
}
hi.push_back(p);
while (size(lo) > 1 && cross(lo.back() - lo.rbegin()[1], p - hi.back()) >= 0) {
lo.pop_back();
}
if (size(lo) == 0 || lo.back().x < p.x) {
lo.push_back(p);
}
}
return std::make_pair(hi, lo);
}
using real = long double;
using P = Point<real>;
constexpr real eps = 0;