Загрузка данных
шаблон по геометрии: struct vec {
int x, y;
long long len2() {
return 1ll * x * x + 1ll * y * y;
}
long double len() {
return sqrt(len2());
}
};
ostream &operator<<(ostream &os, const vec &a) {
return os << a.x << " " << a.y;
}
istream &operator>>(istream &in, vec &a) {
return in >> a.x >> a.y;
}
vec operator+(const vec &a, const vec &b) {
return {a.x + b.x, a.y + b.y};
}
vec operator-(const vec &a, const vec &b) {
return {a.x - b.x, a.y - b.y};
}
vec operator*(const vec &a, const int &k) {
return {a.x * k, a.y * k};
}
vec operator*(const int &k, const vec &a) {
return {a.x * k, a.y * k};
}
long long operator*(const vec &a, const vec &b) {
return 1ll * a.x * b.x + 1ll * a.y * b.y;
}
long long operator%(const vec &a, const vec &b) {
return 1ll * a.x * b.y - 1ll * a.y * b.x;
}
проверить находится ли точка в многоугольнике: bool Func(pii x, vpii &v) {
int n = v.size();
if (vec(v[1] - v[0], x - v[0]) < 0) {
return false;
}
if (vec(v[n - 1] - v[0], x - v[0]) > 0) {
return false;
}
int l = 1, r = n - 1;
while (l + 1 < r) {
int mid = (l + r) / 2;
if (vec(v[mid] - v[0], x - v[0]) >= 0) {
l = mid;
} else {
r = mid;
}
}
return vec(v[l + 1] - v[l], x - v[l]) > 0;
}
выпуклая оболочка и ее площадь:
struct Node {
ll a, b;
};
ll vec(Node a, Node b) {
return a.a * b.b - a.b * b.a;
}
Node operator-(Node a, Node b) {
return {a.a - b.a, a.b - b.b};
}
bool cmp(Node &a, Node &b) {
if (a.a == b.a) {
return a.b < b.b;
}
return a.a < b.a;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
vector<Node> v;
for (int i = 0; i < n; i++) {
int a, b;
cin >> a >> b;
v.emplace_back(a, b);
}
sort(v.begin(), v.end(), cmp);
vint p;
p.push_back(0);
for (int i = 1; i < n; i++) {
while (p.size() >= 2 && vec(v[i] - v[p[p.size() - 2]], v[p.back()] - v[p[p.size() - 2]]) >= 0) {
p.pop_back();
}
p.push_back(i);
}
unsigned int t = p.size();
for (int i = n - 2; i >= 0; i--) {
while (p.size() > t && vec(v[i] - v[p[p.size() - 2]], v[p.back()] - v[p[p.size() - 2]]) >= 0) {
p.pop_back();
}
p.push_back(i);
}
p.pop_back();
ll ans = 0;
n = p.size();
cout << n << '\n';
for (int i = 0; i < n; i++) {
ans += vec(v[p[i]], v[p[(i + 1) % n]]);
}
for (int x : p) {
cout << v[x].a << ' ' << v[x].b << '\n';
}
cout << fixed << setprecision(10) << abs((ld) ans / 2.0);
}
точки сочленения: int k = 0;
vector<bool> used, ans;
vector<int> up, d;
vector<vector<int>> g;
void dfs(int u, int p) {
int children = 0;
used[u] = true;
up[u] = d[u] = (p == -1 ? 0 : d[p] + 1);
for (const int v : g[u]) {
if (v == p) {
continue;
}
if (used[v]) {
up[u] = min(up[u], d[v]);
} else {
dfs(v, u);
children++;
up[u] = min(up[u], up[v]);
if (d[u] <= up[v] && p != -1) {
if (!ans[u]) {
k++;
}
ans[u] = true;
}
}
if (p == -1 && children > 1) {
if (!ans[u]) {
k++;
}
ans[u] = true;
}
}
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, m, u, v;
cin >> n >> m;
used.assign(n, false);
ans.assign(n, false);
g.resize(n);
up.resize(n);
d.resize(n);
for (int i = 0; i < m; i++) {
cin >> u >> v;
u--;
v--;
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 0; i < n; i++) {
if (!used[i]) {
dfs(i, -1);
}
}
cout << k << '\n';
for (int i = 0; i < n; i++) {
if (ans[i]) {
cout << i + 1 << "\n";
}
}
}
мосты:
int k = 0;
vector<bool> used;
vector<int> up, d;
vector<pair<int, int>> ans;
vector<vector<int>> g;
map<pair<int, int>, int> mp;
void dfs(int u, int p) {
used[u] = true;
up[u] = d[u] = (p == -1 ? 0 : d[p] + 1);
for (int v : g[u]) {
if (v == p) {
continue;
}
if (used[v]) {
up[u] = min(up[u], d[v]);
} else {
dfs(v, u);
up[u] = min(up[u], up[v]);
if (d[u] < up[v]) {
ans.push_back({min(u, v), max(u, v)});
}
}
}
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, m, u, v;
cin >> n >> m;
used.assign(n, false);
g.resize(n);
up.resize(n);
d.resize(n);
for (int i = 0; i < m; i++) {
cin >> u >> v;
u--;
v--;
g[u].push_back(v);
g[v].push_back(u);
mp[{min(u, v), max(u, v)}] = i + 1;
}
for (int i = 0; i < n; i++) {
if (!used[i]) {
dfs(i, -1);
}
}
vector<int> a;
n = ans.size();
for (int i = 0; i < n; i++) {
a.push_back(mp[ans[i]]);
}
sort(a.begin(), a.end());
n = a.size();
cout << n << '\n';
for (int i = 0; i < n; i++) {
cout << a[i] << " ";
}
}
пересечение прямых:
vec A, B, C, D;
cin >> A >> B >> C >> D;
vec AB = B - A;
vec CD = D - C;
vec AC = C - A;
if (AB % CD == 0) {
if (AC % CD == 0) {
cout << 2;
return 0;
}
cout << 0;
return 0;
}
cout << 1 << " ";
ld t = (ld) (AC % CD) / (AB % CD);
cout << A + (AB ^ t);
неявный ДД: struct Node {
int prior, val, sz;
Node *l = nullptr, *r = nullptr;
explicit Node(const int _key) { prior = rand(), val = _key, sz = 1; }
};
Node *root = nullptr;
using Pair = pair<Node *, Node *>;
int get_sz(Node *x) {
if (x == nullptr) {
return 0;
}
return x->sz;
}
void upd(Node *v) {
if (v) {
v->sz = get_sz(v->l) + get_sz(v->r) + 1;
}
}
Node *merge(Node *l, Node *r) {
if (!l) {
return r;
}
if (!r) {
return l;
}
if (l->prior > r->prior) {
l->r = merge(l->r, r);
upd(l);
return l;
}
r->l = merge(l, r->l);
upd(r);
return r;
}
Pair split(Node *p, int k) {
if (!p) {
return {nullptr, nullptr};
}
int x = get_sz(p->l) + 1;
if (x <= k) {
Pair q = split(p->r, k - x);
p->r = q.first;
upd(p);
return {p, q.second};
}
Pair q = split(p->l, k);
p->l = q.second;
upd(p);
return {q.first, p};
}
касательные к окружности из точки: // Дано: x0, y0, R (окружность) и x1, y1 (точка вне окружности)
// 1. Дистанция и углы
double d = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2));
double alpha = atan2(y1 - y0, x1 - x0);
double phi = acos(R / d);
// 2. Координаты первой точки касания
double xt1 = x0 + R * cos(alpha + phi);
double yt1 = y0 + R * sin(alpha + phi);
// 3. Координаты второй точки касания
double xt2 = x0 + R * cos(alpha - phi);
double yt2 = y0 + R * sin(alpha - phi);
хеши, задача сравнение подстрок: const int P = 101;
const int MOD = 1000000007;
vector<int> sp, h;
int get_hash(int r, int l) {
return ((h[r] - 1ll * (1ll * h[l] * sp[r - l]) % MOD) + MOD) % MOD;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
string s;
cin >> s;
int n = s.length();
h.resize(n + 1);
sp.resize(n + 1);
sp[0] = 1;
h[0] = 0;
for (int i = 1; i <= n; i++) {
h[i] = (1ll * h[i - 1] * P % MOD + s[i - 1]) % MOD;
sp[i] = (1ll * sp[i - 1] * P) % MOD;
}
int k, l1, r1, l2, r2;
cin >> k;
while (k--) {
cin >> l1 >> r1 >> l2 >> r2;
l1--;
l2--;
int m = min(r1 - l1, r2 - l2);
int l = 0, r = m;
while (l + 1 != r) {
int mid = (l + r) / 2;
const int A = get_hash(mid + l1, l1);
const int B = get_hash(mid + l2, l2);
if (A == B) {
l = mid;
} else {
r = mid;
}
}
int ans = r;
const int A = get_hash(ans + l1, l1);
const int B = get_hash(ans + l2, l2);
if (A != B) {
ans = l;
}
if (ans == m) {
if (r1 - l1 > r2 - l2) {
cout << "No\n";
} else if (r1 - l1 < r2 - l2) {
cout << "No\n";
} else {
cout << "Yes\n";
}
} else {
cout << "No\n";
}
}
}
максимальное независимое множество, все остальные вершины - минимальное вершиное покрытие:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<vector<int>> g;
vector<int> match_r, match_l;
vector<bool> used, visited_l, visited_r;
// Алгоритм Куна для поиска паросочетания
bool dfs_kuhn(int v) {
if (used[v]) return false;
used[v] = true;
for (int to : g[v]) {
if (match_r[to] == -1 || dfs_kuhn(match_r[to])) {
match_r[to] = v;
match_l[v] = to;
return true;
}
}
return false;
}
// Обход для поиска МВП/МНМ
void dfs_mis(int v) {
visited_l[v] = true;
for (int to : g[v]) {
// Идем по ребру не из паросочетания (L -> R)
if (match_l[v] != to && !visited_r[to]) {
visited_r[to] = true;
// Идем по ребру из паросочетания (R -> L)
if (match_r[to] != -1) dfs_mis(match_r[to]);
}
}
}
int main() {
int n, m, k; // n - левая доля, m - правая, k - ребра
cin >> n >> m >> k;
g.resize(n);
match_r.assign(m, -1);
match_l.assign(n, -1);
for (int i = 0; i < k; ++i) {
int u, v; cin >> u >> v;
g[u].push_back(v);
}
// 1. Максимальное паросочетание
for (int i = 0; i < n; ++i) {
used.assign(n, false);
dfs_kuhn(i);
}
// 2. Поиск МНМ
visited_l.assign(n, false);
visited_r.assign(m, false);
for (int i = 0; i < n; ++i) {
if (match_l[i] == -1) dfs_mis(i);
}
cout << "Вершины МНМ в левой доле: ";
for (int i = 0; i < n; i++) if (visited_l[i]) cout << i << " ";
cout << "\nВершины МНМ в правой доле: ";
for (int i = 0; i < m; i++) if (!visited_r[i]) cout << i << " ";
return 0;
}
LCA - сумма чисел в вершинах на пути:
vector<vint> gr;
vint d, p;
void dfs(ll v) {
for (ll u : gr[v]) {
if (u == p[v]) {
continue;
}
d[u] = d[v] + 1;
p[u] = v;
dfs(u);
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
gr.assign(n, {});
d.assign(n, 0);
p.assign(n, 0);
vint v(n);
for (int i = 0; i < n; i++) {
cin >> v[i];
}
for (int i = 1; i < n; i++) {
int a, b;
cin >> a >> b;
a--;
b--;
gr[a].push_back(b);
gr[b].push_back(a);
}
dfs(0);
int l = log2(n) + 1;
vector<vpii> dp(n, vpii(l, {0, 0}));
for (int i = 1; i < n; i++) {
dp[i][0].first = p[i];
dp[i][0].second = v[p[i]];
}
for (int i = 1; i < l; i++) {
for (int j = 0; j < n; j++) {
dp[j][i] = dp[dp[j][i - 1].first][i - 1];
dp[j][i].second += dp[j][i - 1].second;
}
}
int m;
cin >> m;
while (m--) {
int x, y;
cin >> x >> y;
x--;
y--;
if (x == y) {
cout << v[x] << '\n';
continue;
}
if (d[x] > d[y]) {
swap(x, y);
}
ll sum = v[y];
for (int i = l - 1; i >= 0; i--) {
if (d[dp[y][i].first] >= d[x]) {
sum += dp[y][i].second;
y = dp[y][i].first;
}
}
if (x == y) {
cout << sum << '\n';
continue;
}
sum += v[x];
for (int i = l - 1; i >= 0; i--) {
if (dp[x][i].first != dp[y][i].first) {
sum += dp[y][i].second + dp[x][i].second;
x = dp[x][i].first;
y = dp[y][i].first;
}
}
sum += v[p[x]];
cout << sum << '\n';
}
}
задача RMQ корняха:
int n;
cin >> n;
vint v(n);
int m = n / K + 1;
vint ans(m, INF);
for (int i = 0; i < n; i++) {
cin >> v[i];
ans[i / K] = min(ans[i / K], v[i]);
}
string s;
while (cin >> s) {
if (s[0] == 's') {
int i, x;
cin >> i >> x;
i--;
v[i] = x;
int l = (i / K) * K, r = l + K;
ans[i / K] = INF;
for (int j = l; j < r && j < n; j++) {
ans[i / K] = min(ans[i / K], v[j]);
}
continue;
}
int l, r;
cin >> l >> r;
l--;
r--;
int aw = INF;
for (int i = l; i <= r; i++) {
if (i % K == 0 && i + K - 1 <= r) {
aw = min(aw, ans[i / K]);
i += K - 1;
} else {
aw = min(aw, v[i]);
}
}
cout << aw << '\n';
}
МО, сначала расширяем потом сужаем:
struct Node {
int l, r, i;
};
bool cmp(const Node &a, const Node &b) {
int x = a.l / K, y = b.l / K;
if (x != y) {
return x < y;
}
if (x & 1) {
return a.r < b.r;
}
return a.r > b.r;
}