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 = longdouble;
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;
}
}
template<typename T>
structFenwick {constint n;
std::vector<T> tr;
Fenwick(int n) : n(n), tr(n + 1) {}
voidadd(int x, T c) {
for (int i = x; i <= n; i += i & -i) tr[i] += c;
}
voidadd(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);
}
intfind_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;
}
intfind_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<classInfo>structSegTree {// 下标从1开始constint n;
std::vector<Info> tr;
SegTree(int n) : n(n), tr(4 << (std::__lg(n))) {}
SegTree(int n, conststd::vector<Info> &a) : SegTree(n) {
std::function<void(int, int, int)> build = [&](int u, int l, int r) {
if (l == r) returnvoid(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);
}
voidpushup(int u) { tr[u] = tr[u << 1] + tr[u << 1 | 1]; }
voidmodify(int u, int l, int r, int x, const Info &v) {
if (l == r) returnvoid(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);
}
voidmodify(int x, const Info &v) { modify(1, 1, n, x, v); }
Info query(int l, int r) { return query(1, 1, n, l, r);}
};
structInfo {};
Info operator+(const Info &l, const Info &r) {
return {};
}
懒标记线段树(LazySegTree)
点击展开
template<classInfo, classTag>structLazySegTree {// 下标从1开始constint 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(conststd::vector<Info> &a) : LazySegTree((int)a.size()) {
std::function<void(int, int, int)> build = [&](int u, int l, int r) {
if (l == r) returnvoid(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);
}
voidpushup(int u) { tr[u] = tr[u << 1] + tr[u << 1 | 1]; }
voidapply(int u, const Tag &v) { tr[u].apply(v), tag[u].apply(v); }
voidpushdown(int u) {
apply(u << 1, tag[u]), apply(u << 1 | 1, tag[u]);
tag[u] = Tag();
}
voidmodify(int u, int l, int r, int x, const Info &v) {
if (l == r) returnvoid(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);
}
voidmodify(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);}
voidrangeApply(int u, int l, int r, int ql, int qr, const Tag &v) {
if (l > qr || r < ql) return ;
if (l >= ql && r <= qr) { returnvoid(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);
}
voidrangeApply(int l, int r, const Tag &v) { return rangeApply(1, 1, n, l, r, v); }
};
structTag {voidapply(const Tag &t) {}
};
structInfo {int n;
voidapply(const Tag &t) {}
};
Info operator+(const Info &l, const Info &r) {
return {};
}
状压RMQ
点击展开
template<classT,
classCmp =std::less<T>>
structRMQ {const Cmp cmp = Cmp();
static constexpr unsigned B = 64;
using u64 = unsignedlonglong;
int n;
std::vector<std::vector<T>> a;
std::vector<T> pre, suf, ini;
std::vector<u64> stk;
RMQ() {}
RMQ(conststd::vector<T> &v) {
init(v);
}
voidinit(conststd::vector<T> &v) {
n = v.size();
pre = suf = ini = v;
stk.resize(n);
if (!n) return;
constint M = (n - 1) / B + 1;
constint 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) {
constint l = i * B;
constint 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表
structST {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]);
}
}
}
intaskMax(int l, int r) {
int k = std::__lg(r - l + 1);
returnstd::max(f[l][k], f[r - (1LL << k) + 1][k]);
}
intaskMin(int l, int r) {
int k = std::__lg(r - l + 1);
returnstd::min(g[l][k], g[r - (1LL << k) + 1][k]);
}
intaskGcd(int l, int r) {
int k = std::__lg(r - l + 1);
returnstd::__gcd(h[l][k], h[r - (1LL << k) + 1][k]);
}
};
高精度整数-不含负数(BigInt)
点击展开
structBigInt {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 {
returnfalse;
}
}
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*=(constint &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/=(constint &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%=(constint &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, constint &b) {
return a *= b;
}
friend BigInt operator*(BigInt a, const BigInt &b) {
return a *= b;
}
friend BigInt operator/(BigInt a, constint &b) {
return a /= b;
}
friend int operator%(BigInt a, constint &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)
intpower(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;
voidsieve(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;
}
boolisprime(int n) {
return least[n] == n;
}
筛欧拉函数
std::vector<int> primes, phi, least;
voidsieve(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)
intexgcd(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;
voidsieve(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 boolmiller_rabin(longlong n) {
if (n <= 1 || (n != 2 && n % 2 == 0)) returnfalse;
for (auto a : {3, 5, 7, 11, 13, 17, 19, 23, 29}) {
if (n % a == 0) return n == a;
}
if (n < 31 * 31) returntrue;
longlong d = n - 1;
while (d % 2 == 0) d /= 2;
constexpr longlong bases[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37
};
for (longlong a : bases) {
if (n == a) returntrue;
longlong t = d;
longlong y = 1 % n;
for (longlong_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) returnfalse;
}
returntrue;
}
longlongpollard_rho(longlong n) {
if (n == 1 || miller_rabin(n)) return n;
longlong now = 0;
do {
longlong t = std::gcd(++now, n), r = t;
if (t != 1 && t != n) return t;
longlong 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);
return0;
}
std::vector<longlong> factor(longlong n) {
if (n == 1) return {};
std::vector<longlong> 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 = longlong;
template <classT>
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>
structMInt {int x;
constexpr MInt() : x{} {}
constexpr MInt(i64 x) : x{norm(x % P)} {}
constexpr intnorm(int x)const {
if (x < 0) x += P;
if (x >= P) x -= P;
return x;
}
constexpr intval()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)
点击展开
structComb {int n;
std::vector<Z> _fac, _invfac, _inv;
Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}
Comb(int n) : Comb() { init(n); }
voidinit(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) return0;
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];
intbinom(int n, int m) {
if (n < m || m < 0) {
return0;
}
return1LL * fac[n] * invfac[m] % P * invfac[n - m] % P;
}
intpower(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;
}
voidcombInit() {
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<classT>structPoint {
T x, y;
Point (const T &x_ = 0, const T &y_ = 0) : x(x_), y(y_) {}
template<classU>
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<classT>structLine {
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>
doublelength(const Point<T> &p) {
returnstd::sqrt(square(p));
}
template<class T>
doublelength(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>
boolparallel(const Line<T> &l1, const Line<T> &l2) {
return cross(l1.b - l1.a, l2.b - l2.a) == 0;
}
template<class T>
doubledistance(const Point<T> &a, const Point<T> &b) {
return length(a - b);
}
template<class T>
doubledistancePL(const Point<T> &p, const Line<T> &l) {
returnstd::abs(cross(l.a - l.b, l.a - p)) / length(l);
}
template<class T>
doubledistancePS(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>
intsgn(const Point<T> &a) {
return a.y > 0 || (a.y == 0 && a.x > 0) ? 1 : -1;
}
template<class T>
boolpointOnLineLeft(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>
boolpointOnSegment(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>
boolpointInPolygon(const Point<T> &a, conststd::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]))) {
returntrue;
}
}
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<classT>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>
doubledistanceSS(const Line<T> &l1, const Line<T> &l2) {
if (std::get<0>(segmentIntersection(l1, l2)) != 0) {
return0.0;
}
returnstd::min({distancePS(l1.a, l2), distancePS(l1.b, l2), distancePS(l2.a, l1), distance(l2.b, l1)});
}
template<class T>
boolsegmentInPolygon(const Line<T> &l, conststd::vector<Point<T>> &p) {
int n = size(p);
if (!pointInPolygon(l.a, p) || !pointInPolygon(l.b, p)) {
returnfalse;
}
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) {
returnfalse;
}
if (t == 0) {
continue;
}
if (t == 2) {
if (pointOnSegment(v, l) && v != l.a && v != l.b) {
if (cross(v - u, w - v) > 0) {
returnfalse;
}
}
} else {
if (p1 != u && p1 != v) {
if (pointOnLineLeft(l.a, Line(v, u))
|| pointOnLineLeft(l.b, Line(v, u))) {
returnfalse;
}
} elseif (p1 == v) {
if (l.a == v) {
if (pointOnLineLeft(u, l)) {
if (pointOnLineLeft(w, l)
&& pointOnLineLeft(w, Line(u, v))) {
returnfalse;
}
} else {
if (pointOnLineLeft(w, l)
|| pointOnLineLeft(w, Line(u, v))) {
returnfalse;
}
}
} elseif (l.b == v) {
if (pointOnLineLeft(u, Line(l.b, l.a))) {
if (pointOnLineLeft(w, Line(l.b, l.a))
&& pointOnLineLeft(w, Line(u, v))) {
returnfalse;
}
} else {
if (pointOnLineLeft(w, Line(l.b, l.a))
|| pointOnLineLeft(w, Line(u, v))) {
returnfalse;
}
}
} else {
if (pointOnLineLeft(u, l)) {
if (pointOnLineLeft(w, Line(l.b, l.a))
|| pointOnLineLeft(w, Line(u, v))) {
returnfalse;
}
} else {
if (pointOnLineLeft(w, l)
|| pointOnLineLeft(w, Line(u, v))) {
returnfalse;
}
}
}
}
}
}
returntrue;
}
template<classT>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()));
returnstd::vector(ps.begin(), ps.end());
}
template<class T>
autogetHull(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);
}
}
returnstd::make_pair(hi, lo);
}
using real = longdouble;
using P = Point<real>;
constexpr real eps = 0;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)