// #pragma GCC optimize(2)#include <bits/stdc++.h>using namespace std;#define int long long#define endl '\n'#define all(x) (x).begin(), (x).end()constexpr int MOD = 1e9 + 7;// -9.2e18 ~ 9.2e18void solve(){}signed main(){ cin.tie(0)->ios::sync_with_stdio(0); cout << setiosflags(ios::fixed) << setprecision(2); int TT = 1; // cin >> TT; while (TT--) { solve(); // cout << endl; }}
离散化
vector<int> vals = a;sort(all(vals));vals.erase(unique(all(vals)), vals.end());int C = vals.size();vector<int> b(n);for (int i = 0; i < n; i++){ b[i] = lower_bound(all(vals), a[i]) - vals.begin();}
二分答案
// 二分答案:找最小的可行值(单调性 false ... false, true ... true)long long first_true(long long lo, long long hi, auto check) { while (lo < hi) { long long mid = lo + (hi - lo) / 2; if (check(mid)) hi = mid; else lo = mid + 1; } return lo;}// 找最大的可行值(单调性 true ... true, false ... false)long long last_true(long long lo, long long hi, auto check) { while (lo < hi) { long long mid = lo + (hi - lo + 1) / 2; if (check(mid)) lo = mid; else hi = mid - 1; } return lo;}
ST 表
// ============================================================// ST 表 / Sparse Table(静态区间查询,数组使用 1 下标)// ============================================================// 支持:min、max、gcd、按位与、按位或、区间和、区间异或。// 数组建立后不能修改;有修改操作时应使用线段树或树状数组。//// 用法:// vector<int> v(n + 1); // v[1..n]// STTable st(v, ST_MAX);// cout << st.query(l, r);//// min/max/gcd/and/or 查询是 O(1):// 它们允许用两个可能重叠的区间覆盖 [l,r],重复计算不影响答案。//// sum/xor 查询是 O(log n):// 它们不能重复计算,所以要把 [l,r] 拆成互不重叠的 2 的幂区间。// 实际做题时,静态 sum 推荐前缀和,静态 xor 推荐前缀异或,会比 ST 表更简单。//// 建表 O(n log n),空间 O(n log n)。// ============================================================enum STMode{ ST_MIN, ST_MAX, ST_GCD, ST_AND, ST_OR, ST_SUM, ST_XOR};class STTable{private: int n, LOG; STMode mode; // st[j][i] 表示区间 [i, i + 2^j - 1] 的答案。 vector<vector<int>> st; // 合并左右两个区间的答案。 int merge(int left, int right) const { if (mode == ST_MIN) { return min(left, right); } if (mode == ST_MAX) { return max(left, right); } if (mode == ST_GCD) { return gcd(left, right); } if (mode == ST_AND) { return left & right; } if (mode == ST_OR) { return left | right; } if (mode == ST_SUM) { return left + right; } return left ^ right; } // 这些运算重复计算同一个元素不会改变答案,可以使用 O(1) 重叠查询。 bool can_overlap() const { return mode == ST_MIN or mode == ST_MAX or mode == ST_GCD or mode == ST_AND or mode == ST_OR; }public: // v 使用 1 下标,v[0] 空置。 STTable(const vector<int> &v, STMode mode) : n(v.size() - 1), LOG(__lg(max(1ll, n)) + 1), mode(mode), st(LOG, vector<int>(n + 1)) { for (int i = 1; i <= n; i++) { st[0][i] = v[i]; } // 两个长度为 2^(j-1) 的相邻区间,合并成长度为 2^j 的区间。 for (int j = 1; j < LOG; j++) { int half = 1ll << (j - 1); int len = 1ll << j; for (int i = 1; i + len - 1 <= n; i++) { st[j][i] = merge(st[j - 1][i], st[j - 1][i + half]); } } } // 查询闭区间 [l,r],要求 1 <= l <= r <= n。 int query(int l, int r) const { if (can_overlap()) { int k = __lg(r - l + 1); return merge(st[k][l], st[k][r - (1ll << k) + 1]); } // sum/xor:从左到右取互不重叠的区间。 int ans = 0; int pos = l; for (int j = LOG - 1; j >= 0; j--) { int len = 1ll << j; if (pos + len - 1 <= r) { ans = merge(ans, st[j][pos]); pos += len; } } return ans; }};