diff --git a/.clang-format b/.clang-format index 3b8c3fe..af1c7f2 100644 --- a/.clang-format +++ b/.clang-format @@ -10,7 +10,7 @@ BraceWrapping: BeforeCatch: false BeforeElse: false IndentBraces: false -IndentWidth: 2 +IndentWidth: 4 ColumnLimit: 0 AllowShortIfStatementsOnASingleLine: AllIfsAndElse AllowShortLoopsOnASingleLine: true diff --git a/src/1-ds/erasable_pq.cpp b/src/1-ds/erasable_pq.cpp index 38fbd53..4b148c6 100644 --- a/src/1-ds/erasable_pq.cpp +++ b/src/1-ds/erasable_pq.cpp @@ -1,14 +1,14 @@ #include "../common/common.hpp" template > struct pq_set { - priority_queue, O> q, del; - const T &top() const { return q.top(); } - int size() const { return int(q.size() - del.size()); } - bool empty() const { return !size(); } - void insert(const T x) { q.push(x), flush(); } - void pop() { q.pop(), flush(); } - void erase(const T x) { del.push(x), flush(); } - void flush() { - while (del.size() && q.top() == del.top()) q.pop(), del.pop(); - } + priority_queue, O> q, del; + const T &top() const { return q.top(); } + int size() const { return int(q.size() - del.size()); } + bool empty() const { return !size(); } + void insert(const T x) { q.push(x), flush(); } + void pop() { q.pop(), flush(); } + void erase(const T x) { del.push(x), flush(); } + void flush() { + while (del.size() && q.top() == del.top()) q.pop(), del.pop(); + } }; \ No newline at end of file diff --git a/src/1-ds/fenwick_tree.cpp b/src/1-ds/fenwick_tree.cpp index 7fc997f..3c99e91 100644 --- a/src/1-ds/fenwick_tree.cpp +++ b/src/1-ds/fenwick_tree.cpp @@ -1,65 +1,65 @@ #include "../common/common.hpp" // 1. Fenwick Tree -struct Fenwick { // 0-indexed - int flag, cnt; // array size - vector arr, t; - void build(int n) { - for (flag = 1; flag < n; flag <<= 1, cnt++); - arr.resize(flag); - t.resize(flag); - for (int i = 0; i < n; i++) cin >> arr[i]; - for (int i = 0; i < n; i++) { - t[i] += arr[i]; - if (i | (i + 1) < flag) t[i | (i + 1)] += t[i]; +struct Fenwick { // 0-indexed + int flag, cnt; // array size + vector arr, t; + void build(int n) { + for (flag = 1; flag < n; flag <<= 1, cnt++); + arr.resize(flag); + t.resize(flag); + for (int i = 0; i < n; i++) cin >> arr[i]; + for (int i = 0; i < n; i++) { + t[i] += arr[i]; + if (i | (i + 1) < flag) t[i | (i + 1)] += t[i]; + } } - } - void add(int p, ll value) { // add value at position p - arr[p] += value; - while (p < flag) { - t[p] += value; - p |= p + 1; + void add(int p, ll value) { // add value at position p + arr[p] += value; + while (p < flag) { + t[p] += value; + p |= p + 1; + } } - } - void modify(int p, ll value) { // set value at position p - add(p, value - arr[p]); - } - ll query(int x) { - ll ret = 0; - while (x >= 0) ret += t[x], x = (x & (x + 1)) - 1; - return ret; - } - ll query(int l, int r) { - return query(r) - (l ? query(l - 1) : 0); - } - int kth(int k) { // find the kth smallest number (1-indexed) - assert(t.back() >= k); - int l = 0, r = arr.size(); - for (int i = 0; i <= cnt; i++) { - int mid = (l + r) >> 1; - ll val = mid ? t[mid - 1] : t.back(); - if (val >= k) r = mid; - else l = mid, k -= val; + void modify(int p, ll value) { // set value at position p + add(p, value - arr[p]); + } + ll query(int x) { + ll ret = 0; + while (x >= 0) ret += t[x], x = (x & (x + 1)) - 1; + return ret; + } + ll query(int l, int r) { + return query(r) - (l ? query(l - 1) : 0); + } + int kth(int k) { // find the kth smallest number (1-indexed) + assert(t.back() >= k); + int l = 0, r = arr.size(); + for (int i = 0; i <= cnt; i++) { + int mid = (l + r) >> 1; + ll val = mid ? t[mid - 1] : t.back(); + if (val >= k) r = mid; + else l = mid, k -= val; + } + return l; } - return l; - } }; // 2. Fenwick Tree Range Update Point Query struct FenwickRUPQ { // 1-indexed - int flag; - vector t; - void build(int N) { - flag = N; - t.resize(flag + 1); - } - void modify(int l, int r, int val) { // add a val to all elements in interval [l, r] - for (; l <= flag; l += l & -l) t[l] += val; - for (r++; r <= flag; r += r & -r) t[r] -= val; - } - ll query(int x) { - ll ret = 0; - for (; x; x ^= x & -x) ret += t[x]; - return ret; - } + int flag; + vector t; + void build(int N) { + flag = N; + t.resize(flag + 1); + } + void modify(int l, int r, int val) { // add a val to all elements in interval [l, r] + for (; l <= flag; l += l & -l) t[l] += val; + for (r++; r <= flag; r += r & -r) t[r] -= val; + } + ll query(int x) { + ll ret = 0; + for (; x; x ^= x & -x) ret += t[x]; + return ret; + } }; // 3. 2D Fenwick Tree // INPUT: Given an 2D array of integers of size N * M. @@ -68,63 +68,63 @@ struct FenwickRUPQ { // 1-indexed // OUTPUT: Given the query (1 sx sy ex ey), output the sum of elements from the interval (sx, sy) to (ex, ey) // TIME COMPLEXITY: O(N * M) for initialize fenwick tree, O(logN * logM) for each query. struct Fenwick2D { // 0-indexed - int n, m, real_n, real_m; - vector> arr, t; - void build(int N, int M) { - real_n = N, real_m = M; + int n, m, real_n, real_m; + vector> arr, t; + void build(int N, int M) { + real_n = N, real_m = M; - n = m = 1; - while (n < N) n <<= 1; - while (m < M) m <<= 1; - arr.resize(n, vector(m)); - t.resize(n, vector(m)); + n = m = 1; + while (n < N) n <<= 1; + while (m < M) m <<= 1; + arr.resize(n, vector(m)); + t.resize(n, vector(m)); - for (int i = 0; i < real_n; i++) { - for (int j = 0; j < real_m; j++) { - cin >> arr[i][j]; - } - } - for (int i = 0; i < n; i++) { - for (int j = 0; j < m; j++) { - t[i][j] += arr[i][j]; + for (int i = 0; i < real_n; i++) { + for (int j = 0; j < real_m; j++) { + cin >> arr[i][j]; + } + } + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + t[i][j] += arr[i][j]; - int ni = i | (i + 1), nj = j | (j + 1); - if (ni < n) t[ni][j] += t[i][j]; - if (nj < m) t[i][nj] += t[i][j]; - if (ni < n && nj < m) t[ni][nj] -= t[i][j]; - } + int ni = i | (i + 1), nj = j | (j + 1); + if (ni < n) t[ni][j] += t[i][j]; + if (nj < m) t[i][nj] += t[i][j]; + if (ni < n && nj < m) t[ni][nj] -= t[i][j]; + } + } + } + void add(int x, int y, ll value) { // add value at position (x, y) + assert(0 <= x && x < real_n && 0 <= y && y < real_m); + arr[x][y] += value; + for (int i = x; i < n; i |= i + 1) { + for (int j = y; j < m; j |= j + 1) { + t[i][j] += value; + } + } + } + void modify(int x, int y, ll value) { // set value at position (x, y) + assert(0 <= x && x < real_n && 0 <= y && y < real_m); + add(x, y, value - arr[x][y]); } - } - void add(int x, int y, ll value) { // add value at position (x, y) - assert(0 <= x && x < real_n && 0 <= y && y < real_m); - arr[x][y] += value; - for (int i = x; i < n; i |= i + 1) { - for (int j = y; j < m; j |= j + 1) { - t[i][j] += value; - } + ll query(ll x, ll y) { + assert(0 <= x && x < real_n && 0 <= y && y < real_m); + ll ret = 0; + for (int i = x; i >= 0; i = (i & (i + 1)) - 1) { + for (int j = y; j >= 0; j = (j & (j + 1)) - 1) { + ret += t[i][j]; + } + } + return ret; } - } - void modify(int x, int y, ll value) { // set value at position (x, y) - assert(0 <= x && x < real_n && 0 <= y && y < real_m); - add(x, y, value - arr[x][y]); - } - ll query(ll x, ll y) { - assert(0 <= x && x < real_n && 0 <= y && y < real_m); - ll ret = 0; - for (int i = x; i >= 0; i = (i & (i + 1)) - 1) { - for (int j = y; j >= 0; j = (j & (j + 1)) - 1) { - ret += t[i][j]; - } + ll query(ll sx, ll sy, ll ex, ll ey) { + assert(0 <= sx && sx <= ex && ex < real_n); + assert(0 <= sy && sy <= ey && ey < real_m); + ll ret = query(ex, ey); + if (sx) ret -= query(sx - 1, ey); + if (sy) ret -= query(ex, sy - 1); + if (sx && sy) ret += query(sx - 1, sy - 1); + return ret; } - return ret; - } - ll query(ll sx, ll sy, ll ex, ll ey) { - assert(0 <= sx && sx <= ex && ex < real_n); - assert(0 <= sy && sy <= ey && ey < real_m); - ll ret = query(ex, ey); - if (sx) ret -= query(sx - 1, ey); - if (sy) ret -= query(ex, sy - 1); - if (sx && sy) ret += query(sx - 1, sy - 1); - return ret; - } }; \ No newline at end of file diff --git a/src/1-ds/li_chao_tree.cpp b/src/1-ds/li_chao_tree.cpp index 0cce608..7e46adf 100644 --- a/src/1-ds/li_chao_tree.cpp +++ b/src/1-ds/li_chao_tree.cpp @@ -8,50 +8,50 @@ using Line = pair; constexpr Line e = {0, -1e18}; struct LiChaoTree { - ll f(Line l, ll x) { return l.first * x + l.second; } - struct Node { - ll xl, xr; - int l, r; - Line line; - }; - vector t; - void build(ll xlb, ll xub) { - t.push_back({xlb, xub, -1, -1, e}); - } - void insert(Line newLine, int n = 0) { - ll xl = t[n].xl, xr = t[n].xr; - ll xmid = (xl + xr) >> 1; + ll f(Line l, ll x) { return l.first * x + l.second; } + struct Node { + ll xl, xr; + int l, r; + Line line; + }; + vector t; + void build(ll xlb, ll xub) { + t.push_back({xlb, xub, -1, -1, e}); + } + void insert(Line newLine, int n = 0) { + ll xl = t[n].xl, xr = t[n].xr; + ll xmid = (xl + xr) >> 1; - Line llow = t[n].line, lhigh = newLine; - if (f(llow, xl) >= f(lhigh, xl)) swap(llow, lhigh); + Line llow = t[n].line, lhigh = newLine; + if (f(llow, xl) >= f(lhigh, xl)) swap(llow, lhigh); - if (f(llow, xr) <= f(lhigh, xr)) { - t[n].line = lhigh; - return; - } else if (f(llow, xmid) < f(lhigh, xmid)) { - t[n].line = lhigh; - if (t[n].r == -1) { - t[n].r = sz(t); - t.push_back({xmid + 1, xr, -1, -1, e}); - } - insert(llow, t[n].r); - } else if (f(llow, xmid) >= f(lhigh, xmid)) { - t[n].line = llow; - if (t[n].l == -1) { - t[n].l = sz(t); - t.push_back({xl, xmid, -1, -1, e}); - } - insert(lhigh, t[n].l); + if (f(llow, xr) <= f(lhigh, xr)) { + t[n].line = lhigh; + return; + } else if (f(llow, xmid) < f(lhigh, xmid)) { + t[n].line = lhigh; + if (t[n].r == -1) { + t[n].r = sz(t); + t.push_back({xmid + 1, xr, -1, -1, e}); + } + insert(llow, t[n].r); + } else if (f(llow, xmid) >= f(lhigh, xmid)) { + t[n].line = llow; + if (t[n].l == -1) { + t[n].l = sz(t); + t.push_back({xl, xmid, -1, -1, e}); + } + insert(lhigh, t[n].l); + } } - } - ll query(ll x, int n = 0) { - if (n == -1) return e.second; - ll xl = t[n].xl, xr = t[n].xr; - ll xmid = (xl + xr) >> 1; + ll query(ll x, int n = 0) { + if (n == -1) return e.second; + ll xl = t[n].xl, xr = t[n].xr; + ll xmid = (xl + xr) >> 1; - ll ret = f(t[n].line, x); - if (x <= xmid) ret = max(ret, query(x, t[n].l)); - else ret = max(ret, query(x, t[n].r)); - return ret; - } + ll ret = f(t[n].line, x); + if (x <= xmid) ret = max(ret, query(x, t[n].l)); + else ret = max(ret, query(x, t[n].r)); + return ret; + } }; \ No newline at end of file diff --git a/src/1-ds/merge_sort_tree.cpp b/src/1-ds/merge_sort_tree.cpp index aaa5651..1a91835 100644 --- a/src/1-ds/merge_sort_tree.cpp +++ b/src/1-ds/merge_sort_tree.cpp @@ -5,45 +5,45 @@ constexpr int MAX_MST = 1 << 17; // OUTPUT: For each query (i, j, k), output the number of elements greater than k among elements A_i, A_{i+1}, ..., A_j. // TIME COMPLEXITY: O(nlogn) for initialize Merge Sort Tree, O(log^2n) for each query. struct MergeSortTree { - vector t[MAX_MST << 1]; - void build(const vector &arr) { - for (int i = 0; i < sz(arr); i++) - t[i + 1 + MAX_MST].push_back(arr[i]); - for (int i = MAX_MST - 1; i >= 1; i--) { - t[i].resize(sz(t[i << 1]) + sz(t[i << 1 | 1])); - merge(all(t[i << 1]), all(t[i << 1 | 1]), t[i].begin()); + vector t[MAX_MST << 1]; + void build(const vector &arr) { + for (int i = 0; i < sz(arr); i++) + t[i + 1 + MAX_MST].push_back(arr[i]); + for (int i = MAX_MST - 1; i >= 1; i--) { + t[i].resize(sz(t[i << 1]) + sz(t[i << 1 | 1])); + merge(all(t[i << 1]), all(t[i << 1 | 1]), t[i].begin()); + } + } + int query(int l, int r, int k, int n = 1, int nl = 0, int nr = MAX_MST - 1) { // 0-indexed, query on interval [l, r] + if (nr < l || r < nl) return 0; + if (l <= nl && nr <= r) + return t[n].end() - upper_bound(all(t[n]), k); + int mid = (nl + nr) >> 1; + return query(l, r, k, n << 1, nl, mid) + query(l, r, k, n << 1 | 1, mid + 1, nr); } - } - int query(int l, int r, int k, int n = 1, int nl = 0, int nr = MAX_MST - 1) { // 0-indexed, query on interval [l, r] - if (nr < l || r < nl) return 0; - if (l <= nl && nr <= r) - return t[n].end() - upper_bound(all(t[n]), k); - int mid = (nl + nr) >> 1; - return query(l, r, k, n << 1, nl, mid) + query(l, r, k, n << 1 | 1, mid + 1, nr); - } }; // 2. Iterative Merge Sort Tree // INPUT: Given a sequence A_1, A_2, ..., A_n of length n. Given a query (i, j, k). // OUTPUT: For each query (i, j, k), output the number of elements greater than k among elements A_i, A_{i+1}, ..., A_j. // TIME COMPLEXITY: O(nlogn) for initialize Merge Sort Tree, O(log^2n) for each query. struct MergeSortTreeIter { - vector t[MAX_MST << 1]; - void build(const vector &arr) { - for (int i = 0; i < sz(arr); i++) - t[i + 1 + MAX_MST].push_back(arr[i]); - for (int i = MAX_MST - 1; i >= 1; i--) { - t[i].resize(sz(t[i << 1]) + sz(t[i << 1 | 1])); - merge(all(t[i << 1]), all(t[i << 1 | 1]), t[i].begin()); + vector t[MAX_MST << 1]; + void build(const vector &arr) { + for (int i = 0; i < sz(arr); i++) + t[i + 1 + MAX_MST].push_back(arr[i]); + for (int i = MAX_MST - 1; i >= 1; i--) { + t[i].resize(sz(t[i << 1]) + sz(t[i << 1 | 1])); + merge(all(t[i << 1]), all(t[i << 1 | 1]), t[i].begin()); + } } - } - int query(int l, int r, int k) { // 1-indexed, query on interval [l, r] - l += MAX_MST, r += MAX_MST; - int ret = 0; - while (l <= r) { - if (l & 1) ret += t[l].end() - upper_bound(all(t[l]), k), l++; - if (~r & 1) ret += t[r].end() - upper_bound(all(t[r]), k), r--; - l >>= 1, r >>= 1; + int query(int l, int r, int k) { // 1-indexed, query on interval [l, r] + l += MAX_MST, r += MAX_MST; + int ret = 0; + while (l <= r) { + if (l & 1) ret += t[l].end() - upper_bound(all(t[l]), k), l++; + if (~r & 1) ret += t[r].end() - upper_bound(all(t[r]), k), r--; + l >>= 1, r >>= 1; + } + return ret; } - return ret; - } }; \ No newline at end of file diff --git a/src/1-ds/pbds.cpp b/src/1-ds/pbds.cpp index 87af3a4..bd44aaf 100644 --- a/src/1-ds/pbds.cpp +++ b/src/1-ds/pbds.cpp @@ -10,7 +10,7 @@ st.find_by_order(x); // value of xth element (0-based) // multiset pbds (use "less_equal" and custom "m_erase") using multi_pbds = tree, rb_tree_tag, tree_order_statistics_node_update>; void m_erase(multi_pbds &OS, int val) { - int index = OS.order_of_key(val); - multi_pbds::iterator it = OS.find_by_order(index); - OS.erase(it); + int index = OS.order_of_key(val); + multi_pbds::iterator it = OS.find_by_order(index); + OS.erase(it); } diff --git a/src/1-ds/segment_tree.cpp b/src/1-ds/segment_tree.cpp index b56d659..07eb0fc 100644 --- a/src/1-ds/segment_tree.cpp +++ b/src/1-ds/segment_tree.cpp @@ -2,228 +2,228 @@ int flag; // array size // 1. Segment Tree struct Seg { // 1-indexed - vector t; - void build(int n) { - for (flag = 1; flag < n; flag <<= 1); - t.resize(2 * flag); - for (int i = flag; i < flag + n; i++) cin >> t[i]; - for (int i = flag - 1; i >= 1; i--) t[i] = t[i << 1] + t[i << 1 | 1]; - } - void modify(int p, ll value) { // set value at position p - for (t[p += flag - 1] = value; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1]; - } - ll query(int l, int r, int n = 1, int nl = 1, int nr = flag) { // sum on interval [l, r] - if (r < nl || nr < l) return 0; - if (l <= nl && nr <= r) return t[n]; - int mid = (nl + nr) / 2; - return query(l, r, n << 1, nl, mid) + query(l, r, n << 1 | 1, mid + 1, nr); - } + vector t; + void build(int n) { + for (flag = 1; flag < n; flag <<= 1); + t.resize(2 * flag); + for (int i = flag; i < flag + n; i++) cin >> t[i]; + for (int i = flag - 1; i >= 1; i--) t[i] = t[i << 1] + t[i << 1 | 1]; + } + void modify(int p, ll value) { // set value at position p + for (t[p += flag - 1] = value; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1]; + } + ll query(int l, int r, int n = 1, int nl = 1, int nr = flag) { // sum on interval [l, r] + if (r < nl || nr < l) return 0; + if (l <= nl && nr <= r) return t[n]; + int mid = (nl + nr) / 2; + return query(l, r, n << 1, nl, mid) + query(l, r, n << 1 | 1, mid + 1, nr); + } }; // 2. Iterative Segment Tree constexpr int MAXN = 1010101; // limit for array size struct SegIter { // 0-indexed - int n; // array size - ll t[2 * MAXN]; - void build(int N) { - n = N; - for (int i = 0; i < n; i++) cin >> t[n + i]; - for (int i = n - 1; i >= 1; i--) t[i] = t[i << 1] + t[i << 1 | 1]; - } - void modify(int p, ll value) { // set value at position p - for (t[p += n] = value; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1]; - } - ll query(int l, int r) { // sum on interval [l, r) - ll ret = 0; - for (l += n, r += n; l < r; l >>= 1, r >>= 1) { - if (l & 1) ret += t[l++]; - if (r & 1) ret += t[--r]; - } - return ret; - } + int n; // array size + ll t[2 * MAXN]; + void build(int N) { + n = N; + for (int i = 0; i < n; i++) cin >> t[n + i]; + for (int i = n - 1; i >= 1; i--) t[i] = t[i << 1] + t[i << 1 | 1]; + } + void modify(int p, ll value) { // set value at position p + for (t[p += n] = value; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1]; + } + ll query(int l, int r) { // sum on interval [l, r) + ll ret = 0; + for (l += n, r += n; l < r; l >>= 1, r >>= 1) { + if (l & 1) ret += t[l++]; + if (r & 1) ret += t[--r]; + } + return ret; + } }; // 3. k-th Segment Tree struct SegKth { - vector t; - void build(int n) { - for (flag = 1; flag < n; flag <<= 1); - t.resize(flag << 1); - } - void add(int p, ll value) { // add value at position p - for (t[p += flag - 1] += value; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1]; - } - ll kth(ll k, int n = 1) { // find the kth smallest number (1-indexed) - assert(t[n] >= k); - if (flag <= n) return n - flag + 1; - if (k <= t[n << 1]) return kth(k, n << 1); - else return kth(k - t[n << 1], n << 1 | 1); - } + vector t; + void build(int n) { + for (flag = 1; flag < n; flag <<= 1); + t.resize(flag << 1); + } + void add(int p, ll value) { // add value at position p + for (t[p += flag - 1] += value; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1]; + } + ll kth(ll k, int n = 1) { // find the kth smallest number (1-indexed) + assert(t[n] >= k); + if (flag <= n) return n - flag + 1; + if (k <= t[n << 1]) return kth(k, n << 1); + else return kth(k - t[n << 1], n << 1 | 1); + } }; // 4. Segment Tree with Lazy Propagation struct SegLazy { // 1-indexed - vector t, lazy; - void build(int n) { - for (flag = 1; flag < n; flag <<= 1); - t.resize(2 * flag); - lazy.resize(2 * flag); - for (int i = flag; i < flag + n; i++) cin >> t[i]; - for (int i = flag - 1; i >= 1; i--) t[i] = t[i << 1] + t[i << 1 | 1]; - } - // add a value to all elements in interval [l, r] - void modify(int l, int r, ll value, int n = 1, int nl = 1, int nr = flag) { - propagate(n, nl, nr); - if (r < nl || nr < l) return; - if (l <= nl && nr <= r) { - lazy[n] += value; - propagate(n, nl, nr); - return; - } - int mid = (nl + nr) >> 1; - modify(l, r, value, n << 1, nl, mid); - modify(l, r, value, n << 1 | 1, mid + 1, nr); - t[n] = t[n << 1] + t[n << 1 | 1]; - } - ll query(int l, int r, int n = 1, int nl = 1, int nr = flag) { // sum on interval [l, r] - propagate(n, nl, nr); - if (r < nl || nr < l) return 0; - if (l <= nl && nr <= r) return t[n]; - int mid = (nl + nr) / 2; - return query(l, r, n << 1, nl, mid) + query(l, r, n << 1 | 1, mid + 1, nr); - } - void propagate(int n, int nl, int nr) { - if (lazy[n] != 0) { - if (n < flag) { - lazy[n << 1] += lazy[n]; - lazy[n << 1 | 1] += lazy[n]; - } - t[n] += lazy[n] * (nr - nl + 1); - lazy[n] = 0; - } - } + vector t, lazy; + void build(int n) { + for (flag = 1; flag < n; flag <<= 1); + t.resize(2 * flag); + lazy.resize(2 * flag); + for (int i = flag; i < flag + n; i++) cin >> t[i]; + for (int i = flag - 1; i >= 1; i--) t[i] = t[i << 1] + t[i << 1 | 1]; + } + // add a value to all elements in interval [l, r] + void modify(int l, int r, ll value, int n = 1, int nl = 1, int nr = flag) { + propagate(n, nl, nr); + if (r < nl || nr < l) return; + if (l <= nl && nr <= r) { + lazy[n] += value; + propagate(n, nl, nr); + return; + } + int mid = (nl + nr) >> 1; + modify(l, r, value, n << 1, nl, mid); + modify(l, r, value, n << 1 | 1, mid + 1, nr); + t[n] = t[n << 1] + t[n << 1 | 1]; + } + ll query(int l, int r, int n = 1, int nl = 1, int nr = flag) { // sum on interval [l, r] + propagate(n, nl, nr); + if (r < nl || nr < l) return 0; + if (l <= nl && nr <= r) return t[n]; + int mid = (nl + nr) / 2; + return query(l, r, n << 1, nl, mid) + query(l, r, n << 1 | 1, mid + 1, nr); + } + void propagate(int n, int nl, int nr) { + if (lazy[n] != 0) { + if (n < flag) { + lazy[n << 1] += lazy[n]; + lazy[n << 1 | 1] += lazy[n]; + } + t[n] += lazy[n] * (nr - nl + 1); + lazy[n] = 0; + } + } }; // 5. Persistent Segment Tree // TIME COMPLEXITY: O(n) for initialize PST, O(logn) for each query. // SPACE COMPLEXITY: O(nlogm). -struct PST { // 1-indexed - int flag; // array size - struct Node { - int l, r; - ll val; - }; - vector t; - vector root; +struct PST { // 1-indexed + int flag; // array size + struct Node { + int l, r; + ll val; + }; + vector t; + vector root; - void addNode() { t.push_back({-1, -1, 0}); } - void build(int l, int r, int n, const vector &a) { - assert(0 <= n && n < sz(t)); - if (l == r) { - t[n].val = a[l]; - return; - } - addNode(); - t[n].l = sz(t) - 1; - addNode(); - t[n].r = sz(t) - 1; + void addNode() { t.push_back({-1, -1, 0}); } + void build(int l, int r, int n, const vector &a) { + assert(0 <= n && n < sz(t)); + if (l == r) { + t[n].val = a[l]; + return; + } + addNode(); + t[n].l = sz(t) - 1; + addNode(); + t[n].r = sz(t) - 1; - int mid = (l + r) >> 1; - build(l, mid, t[n].l, a); - build(mid + 1, r, t[n].r, a); - t[n].val = t[t[n].l].val + t[t[n].r].val; - } - void build(int Flag, const vector &a) { - addNode(); - root.push_back(sz(t) - 1); - flag = Flag; - build(1, flag, root[0], a); - } - void modify(int p, ll val, int l, int r, int n1, int n2) { - assert(0 <= n1 && n1 < sz(t)); - assert(0 <= n2 && n2 < sz(t)); - if (p < l || r < p) { - t[n2] = t[n1]; - return; - } - if (l == r) { - t[n2].val = val; - return; - } - int mid = (l + r) >> 1; - if (p <= mid) { - t[n2].r = t[n1].r; - addNode(); - t[n2].l = sz(t) - 1; - modify(p, val, l, mid, t[n1].l, t[n2].l); - } else { - t[n2].l = t[n1].l; - addNode(); - t[n2].r = sz(t) - 1; - modify(p, val, mid + 1, r, t[n1].r, t[n2].r); - } - t[n2].val = t[t[n2].l].val + t[t[n2].r].val; - } - void modify(int p, ll val) { - addNode(); - root.push_back(sz(t) - 1); - modify(p, val, 1, flag, root[sz(root) - 2], root[sz(root) - 1]); - } - ll query(int l, int r, int n, int nl, int nr) { - assert(0 <= n && n < sz(t)); - if (r < nl || nr < l) return 0; - if (l <= nl && nr <= r) return t[n].val; - int mid = (nl + nr) >> 1; - return query(l, r, t[n].l, nl, mid) + query(l, r, t[n].r, mid + 1, nr); - } - ll query(int l, int r, int n) { - assert(n < sz(root)); - return query(l, r, root[n], 1, flag); - } + int mid = (l + r) >> 1; + build(l, mid, t[n].l, a); + build(mid + 1, r, t[n].r, a); + t[n].val = t[t[n].l].val + t[t[n].r].val; + } + void build(int Flag, const vector &a) { + addNode(); + root.push_back(sz(t) - 1); + flag = Flag; + build(1, flag, root[0], a); + } + void modify(int p, ll val, int l, int r, int n1, int n2) { + assert(0 <= n1 && n1 < sz(t)); + assert(0 <= n2 && n2 < sz(t)); + if (p < l || r < p) { + t[n2] = t[n1]; + return; + } + if (l == r) { + t[n2].val = val; + return; + } + int mid = (l + r) >> 1; + if (p <= mid) { + t[n2].r = t[n1].r; + addNode(); + t[n2].l = sz(t) - 1; + modify(p, val, l, mid, t[n1].l, t[n2].l); + } else { + t[n2].l = t[n1].l; + addNode(); + t[n2].r = sz(t) - 1; + modify(p, val, mid + 1, r, t[n1].r, t[n2].r); + } + t[n2].val = t[t[n2].l].val + t[t[n2].r].val; + } + void modify(int p, ll val) { + addNode(); + root.push_back(sz(t) - 1); + modify(p, val, 1, flag, root[sz(root) - 2], root[sz(root) - 1]); + } + ll query(int l, int r, int n, int nl, int nr) { + assert(0 <= n && n < sz(t)); + if (r < nl || nr < l) return 0; + if (l <= nl && nr <= r) return t[n].val; + int mid = (nl + nr) >> 1; + return query(l, r, t[n].l, nl, mid) + query(l, r, t[n].r, mid + 1, nr); + } + ll query(int l, int r, int n) { + assert(n < sz(root)); + return query(l, r, root[n], 1, flag); + } }; // 6. Dynamic Segment Tree constexpr int MAXL = 1, MAXR = 1000000; struct Node { - ll x; - int l, r; + ll x; + int l, r; }; struct DySeg { - vector t = {{0, -1, -1}, {0, -1, -1}}; - void modify(int p, ll x, int n = 1, int nl = MAXL, int nr = MAXR) { - if (p < nl || nr < p) return; - t[n].x += x; - if (nl < nr) { - int mid = (nl + nr) >> 1; - if (p <= mid) { - if (t[n].l == -1) { - t[n].l = sz(t); - t.push_back({0, -1, -1}); + vector t = {{0, -1, -1}, {0, -1, -1}}; + void modify(int p, ll x, int n = 1, int nl = MAXL, int nr = MAXR) { + if (p < nl || nr < p) return; + t[n].x += x; + if (nl < nr) { + int mid = (nl + nr) >> 1; + if (p <= mid) { + if (t[n].l == -1) { + t[n].l = sz(t); + t.push_back({0, -1, -1}); + } + modify(p, x, t[n].l, nl, mid); + } else { + if (t[n].r == -1) { + t[n].r = sz(t); + t.push_back({0, -1, -1}); + } + modify(p, x, t[n].r, mid + 1, nr); + } } - modify(p, x, t[n].l, nl, mid); - } else { - if (t[n].r == -1) { - t[n].r = sz(t); - t.push_back({0, -1, -1}); + } + ll query(int l, int r, int n = 1, int nl = MAXL, int nr = MAXR) { + if (r < nl || nr < l) return 0; + if (l <= nl && nr <= r) return t[n].x; + int mid = (nl + nr) >> 1; + ll ret = 0; + if (l <= mid) { + if (t[n].l == -1) { + t[n].l = sz(t); + t.push_back({0, -1, -1}); + } + ret += query(l, r, t[n].l, nl, mid); + } + if (mid + 1 <= r) { + if (t[n].r == -1) { + t[n].r = sz(t); + t.push_back({0, -1, -1}); + } + ret += query(l, r, t[n].r, mid + 1, nr); } - modify(p, x, t[n].r, mid + 1, nr); - } - } - } - ll query(int l, int r, int n = 1, int nl = MAXL, int nr = MAXR) { - if (r < nl || nr < l) return 0; - if (l <= nl && nr <= r) return t[n].x; - int mid = (nl + nr) >> 1; - ll ret = 0; - if (l <= mid) { - if (t[n].l == -1) { - t[n].l = sz(t); - t.push_back({0, -1, -1}); - } - ret += query(l, r, t[n].l, nl, mid); - } - if (mid + 1 <= r) { - if (t[n].r == -1) { - t[n].r = sz(t); - t.push_back({0, -1, -1}); - } - ret += query(l, r, t[n].r, mid + 1, nr); - } - return ret; - } + return ret; + } }; \ No newline at end of file diff --git a/src/1-ds/segment_tree_2d.cpp b/src/1-ds/segment_tree_2d.cpp index 3a1a73c..3534f69 100644 --- a/src/1-ds/segment_tree_2d.cpp +++ b/src/1-ds/segment_tree_2d.cpp @@ -1,111 +1,111 @@ #include "../common/common.hpp" // 1. 2D Segment Tree struct Seg2D { // 0-indexed - int n; - vector> t; - Seg2D(int n) : n(n), t(2 * n, vector(2 * n)) {} - // You must pass an n x n 2D vector as the argument - void build(vector> &val) { - t.resize(2 * n, vector(2 * n)); - for (int i = 0; i < n; i++) - for (int j = 0; j < n; j++) - t[i + n][j + n] = val[i][j]; - // Handle segments that are leaf nodes of the outer segment tree - for (int i = n; i < 2 * n; i++) - for (int j = n - 1; j > 0; j--) - t[i][j] = t[i][j << 1] + t[i][j << 1 | 1]; - // Handle segments that are non-leaf nodes of the outer segment tree - for (int i = n - 1; i > 0; i--) - for (int j = 1; j < 2 * n; j++) - t[i][j] = t[i << 1][j] + t[i << 1 | 1][j]; - } - // Change the value at (x, y) to val - void modify(int x, int y, ll val) { - t[x + n][y + n] = val; - // Handle a leaf of the outer segment tree - for (int i = y + n; i > 1; i >>= 1) - t[x + n][i >> 1] = t[x + n][i] + t[x + n][i ^ 1]; - // Handle segments that are non-leaf nodes of the outer segment tree - for (x = x + n; x > 1; x >>= 1) - for (int i = y + n; i >= 1; i >>= 1) - t[x >> 1][i] = t[x][i] + t[x ^ 1][i]; - } - ll query1D(int x, int y1, int y2) { - ll ret = 0; - for (y1 += n, y2 += n + 1; y1 < y2; y1 >>= 1, y2 >>= 1) { - if (y1 & 1) ret += t[x][y1++]; - if (y2 & 1) ret += t[x][--y2]; + int n; + vector> t; + Seg2D(int n) : n(n), t(2 * n, vector(2 * n)) {} + // You must pass an n x n 2D vector as the argument + void build(vector> &val) { + t.resize(2 * n, vector(2 * n)); + for (int i = 0; i < n; i++) + for (int j = 0; j < n; j++) + t[i + n][j + n] = val[i][j]; + // Handle segments that are leaf nodes of the outer segment tree + for (int i = n; i < 2 * n; i++) + for (int j = n - 1; j > 0; j--) + t[i][j] = t[i][j << 1] + t[i][j << 1 | 1]; + // Handle segments that are non-leaf nodes of the outer segment tree + for (int i = n - 1; i > 0; i--) + for (int j = 1; j < 2 * n; j++) + t[i][j] = t[i << 1][j] + t[i << 1 | 1][j]; } - return ret; - } - // sum on rectangle [x1, x2] × [y1, y2] (0-indexed, inclusive) - ll query(int x1, int x2, int y1, int y2) { - ll ret = 0; - for (x1 += n, x2 += n + 1; x1 < x2; x1 >>= 1, x2 >>= 1) { - if (x1 & 1) ret += query1D(x1++, y1, y2); - if (x2 & 1) ret += query1D(--x2, y1, y2); + // Change the value at (x, y) to val + void modify(int x, int y, ll val) { + t[x + n][y + n] = val; + // Handle a leaf of the outer segment tree + for (int i = y + n; i > 1; i >>= 1) + t[x + n][i >> 1] = t[x + n][i] + t[x + n][i ^ 1]; + // Handle segments that are non-leaf nodes of the outer segment tree + for (x = x + n; x > 1; x >>= 1) + for (int i = y + n; i >= 1; i >>= 1) + t[x >> 1][i] = t[x][i] + t[x ^ 1][i]; + } + ll query1D(int x, int y1, int y2) { + ll ret = 0; + for (y1 += n, y2 += n + 1; y1 < y2; y1 >>= 1, y2 >>= 1) { + if (y1 & 1) ret += t[x][y1++]; + if (y2 & 1) ret += t[x][--y2]; + } + return ret; + } + // sum on rectangle [x1, x2] × [y1, y2] (0-indexed, inclusive) + ll query(int x1, int x2, int y1, int y2) { + ll ret = 0; + for (x1 += n, x2 += n + 1; x1 < x2; x1 >>= 1, x2 >>= 1) { + if (x1 & 1) ret += query1D(x1++, y1, y2); + if (x2 & 1) ret += query1D(--x2, y1, y2); + } + return ret; } - return ret; - } }; // 2. 2D Segment Tree with Coordinate Compression // You must perform all fake_* calls first, then call prepare(), and only after that call modify and query struct Seg2DComp { // 0-indexed - int n; - vector> a; - vector> used; - Seg2DComp(int n) : n(n), a(2 * n), used(2 * n) {} - void fake_modify(int x, int y) { - for (x += n; x >= 1; x >>= 1) - used[x].push_back(y); - } - void fake_query(int x1, int x2, int y1, int y2) { - for (x1 += n, x2 += n + 1; x1 < x2; x1 >>= 1, x2 >>= 1) { - if (x1 & 1) { - used[x1].push_back(y1); - used[x1++].push_back(y2); - } - if (x2 & 1) { - used[--x2].push_back(y1); - used[x2].push_back(y2); - } + int n; + vector> a; + vector> used; + Seg2DComp(int n) : n(n), a(2 * n), used(2 * n) {} + void fake_modify(int x, int y) { + for (x += n; x >= 1; x >>= 1) + used[x].push_back(y); + } + void fake_query(int x1, int x2, int y1, int y2) { + for (x1 += n, x2 += n + 1; x1 < x2; x1 >>= 1, x2 >>= 1) { + if (x1 & 1) { + used[x1].push_back(y1); + used[x1++].push_back(y2); + } + if (x2 & 1) { + used[--x2].push_back(y1); + used[x2].push_back(y2); + } + } } - } - void prepare() { - for (int i = 0; i < 2 * n; i++) { - if (!used[i].empty()) { - sort(used[i].begin(), used[i].end()); - used[i].erase(unique(all(used[i])), used[i].end()); - } - used[i].shrink_to_fit(); - a[i].resize(sz(used[i]) << 1); + void prepare() { + for (int i = 0; i < 2 * n; i++) { + if (!used[i].empty()) { + sort(used[i].begin(), used[i].end()); + used[i].erase(unique(all(used[i])), used[i].end()); + } + used[i].shrink_to_fit(); + a[i].resize(sz(used[i]) << 1); + } } - } - void modify(int x, int y, ll val) { - for (x += n; x >= 1; x >>= 1) { - int i = lower_bound(all(used[x]), y) - used[x].begin() + sz(used[x]); - for (a[x][i] = val; i > 1; i >>= 1) { - a[x][i >> 1] = a[x][i] + a[x][i ^ 1]; - } + void modify(int x, int y, ll val) { + for (x += n; x >= 1; x >>= 1) { + int i = lower_bound(all(used[x]), y) - used[x].begin() + sz(used[x]); + for (a[x][i] = val; i > 1; i >>= 1) { + a[x][i >> 1] = a[x][i] + a[x][i ^ 1]; + } + } } - } - ll query1D(int x, int y1, int y2) { - ll ret = 0; - y1 = lower_bound(all(used[x]), y1) - used[x].begin(); - y2 = lower_bound(all(used[x]), y2) - used[x].begin(); - for (y1 += sz(used[x]), y2 += sz(used[x]) + 1; y1 < y2; y1 >>= 1, y2 >>= 1) { - if (y1 & 1) ret += a[x][y1++]; - if (y2 & 1) ret += a[x][--y2]; + ll query1D(int x, int y1, int y2) { + ll ret = 0; + y1 = lower_bound(all(used[x]), y1) - used[x].begin(); + y2 = lower_bound(all(used[x]), y2) - used[x].begin(); + for (y1 += sz(used[x]), y2 += sz(used[x]) + 1; y1 < y2; y1 >>= 1, y2 >>= 1) { + if (y1 & 1) ret += a[x][y1++]; + if (y2 & 1) ret += a[x][--y2]; + } + return ret; } - return ret; - } - // sum on rectangle [x1, x2] × [y1, y2] (0-indexed, inclusive) - ll query(int x1, int x2, int y1, int y2) { - ll ret = 0; - for (x1 += n, x2 += n + 1; x1 < x2; x1 >>= 1, x2 >>= 1) { - if (x1 & 1) ret += query1D(x1++, y1, y2); - if (x2 & 1) ret += query1D(--x2, y1, y2); + // sum on rectangle [x1, x2] × [y1, y2] (0-indexed, inclusive) + ll query(int x1, int x2, int y1, int y2) { + ll ret = 0; + for (x1 += n, x2 += n + 1; x1 < x2; x1 >>= 1, x2 >>= 1) { + if (x1 & 1) ret += query1D(x1++, y1, y2); + if (x2 & 1) ret += query1D(--x2, y1, y2); + } + return ret; } - return ret; - } }; \ No newline at end of file diff --git a/src/1-ds/union_find.cpp b/src/1-ds/union_find.cpp index bcdffdc..8edcf54 100644 --- a/src/1-ds/union_find.cpp +++ b/src/1-ds/union_find.cpp @@ -1,18 +1,18 @@ #include "../common/common.hpp" struct UF { - vector uf; - void build(int n) { - uf.clear(); - uf.resize(n + 1, -1); - } - int find(int v) { - if (uf[v] < 0) return v; - return uf[v] = find(uf[v]); - } - void merge(int u, int v) { - int U = find(u), V = find(v); - if (U == V) return; - uf[U] += uf[V]; - uf[V] = U; - } + vector uf; + void build(int n) { + uf.clear(); + uf.resize(n + 1, -1); + } + int find(int v) { + if (uf[v] < 0) return v; + return uf[v] = find(uf[v]); + } + void merge(int u, int v) { + int U = find(u), V = find(v); + if (U == V) return; + uf[U] += uf[V]; + uf[V] = U; + } }; \ No newline at end of file diff --git a/src/2-graph/bcc.cpp b/src/2-graph/bcc.cpp index 19a2a96..8f59e69 100644 --- a/src/2-graph/bcc.cpp +++ b/src/2-graph/bcc.cpp @@ -17,53 +17,53 @@ vector> bcc; set aPoint; set aEdge; void input() { - cin >> n >> m; - for (int i = 0; i < m; i++) { - int u, v; - cin >> u >> v; - adj[u].push_back(v); - adj[v].push_back(u); - } + cin >> n >> m; + for (int i = 0; i < m; i++) { + int u, v; + cin >> u >> v; + adj[u].push_back(v); + adj[v].push_back(u); + } } int dfsn[MAXV], dCnt; stack stk; int dfs(int now, int prv) { - int ret = dfsn[now] = ++dCnt; - int childCnt = 0; - for (int next : adj[now]) { - if (next == prv) continue; - // If an edge { now, next } has not yet been visited, puts an edge on the stack. - if (dfsn[now] > dfsn[next]) stk.push({now, next}); - // Back edge - if (dfsn[next] != -1) ret = min(ret, dfsn[next]); - // Tree edge - else { - childCnt++; - int tmp = dfs(next, now); - ret = min(ret, tmp); - if (prv != -1 && tmp >= dfsn[now]) - aPoint.insert(now); - if (tmp > dfsn[now]) - aEdge.insert({min(now, next), max(now, next)}); - // If next cannot go to ancestor node of now, find BCC - if (tmp >= dfsn[now]) { - vector nowBCC; - while (true) { - pii t = stk.top(); - stk.pop(); - nowBCC.push_back(t); - if (t == make_pair(now, next)) break; + int ret = dfsn[now] = ++dCnt; + int childCnt = 0; + for (int next : adj[now]) { + if (next == prv) continue; + // If an edge { now, next } has not yet been visited, puts an edge on the stack. + if (dfsn[now] > dfsn[next]) stk.push({now, next}); + // Back edge + if (dfsn[next] != -1) ret = min(ret, dfsn[next]); + // Tree edge + else { + childCnt++; + int tmp = dfs(next, now); + ret = min(ret, tmp); + if (prv != -1 && tmp >= dfsn[now]) + aPoint.insert(now); + if (tmp > dfsn[now]) + aEdge.insert({min(now, next), max(now, next)}); + // If next cannot go to ancestor node of now, find BCC + if (tmp >= dfsn[now]) { + vector nowBCC; + while (true) { + pii t = stk.top(); + stk.pop(); + nowBCC.push_back(t); + if (t == make_pair(now, next)) break; + } + bcc.push_back(nowBCC); + } } - bcc.push_back(nowBCC); - } } - } - if (prv == -1 && childCnt > 1) - aPoint.insert(now); - return ret; + if (prv == -1 && childCnt > 1) + aPoint.insert(now); + return ret; } void getBCC() { - memset(dfsn, -1, sizeof(dfsn)); - for (int v = 1; v <= n; v++) - if (dfsn[v] == -1) dfs(v, -1); + memset(dfsn, -1, sizeof(dfsn)); + for (int v = 1; v <= n; v++) + if (dfsn[v] == -1) dfs(v, -1); } \ No newline at end of file diff --git a/src/2-graph/dijkstra_bellman_ford_floyd_warshall.cpp b/src/2-graph/dijkstra_bellman_ford_floyd_warshall.cpp index 264b82d..b2f49c7 100644 --- a/src/2-graph/dijkstra_bellman_ford_floyd_warshall.cpp +++ b/src/2-graph/dijkstra_bellman_ford_floyd_warshall.cpp @@ -5,20 +5,20 @@ vector> adj[202020]; vector dist(202020, (ll)1e18); void dijkstra(int st) { - priority_queue, vector>, greater>> pq; - pq.push({0, st}); - dist[st] = 0; - while (!pq.empty()) { - auto [w, v] = pq.top(); - pq.pop(); - if (w > dist[v]) continue; - for (auto &i : adj[v]) { - if (dist[i.v] > w + i.w) { - dist[i.v] = w + i.w; - pq.push({w + i.w, i.v}); - } + priority_queue, vector>, greater>> pq; + pq.push({0, st}); + dist[st] = 0; + while (!pq.empty()) { + auto [w, v] = pq.top(); + pq.pop(); + if (w > dist[v]) continue; + for (auto &i : adj[v]) { + if (dist[i.v] > w + i.w) { + dist[i.v] = w + i.w; + pq.push({w + i.w, i.v}); + } + } } - } } // 2. Bellman-Ford Algorithm @@ -30,22 +30,22 @@ int n, m; vector> adj[101010]; vector upper(101010, INF); int bellmanFord() { - upper[1] = 0; - int update = 1; - for (int i = 0; i <= n; i++) { - update = 0; - for (int v = 1; v <= n; v++) { - if (upper[v] == INF) continue; - for (auto &i : adj[v]) { - if (upper[i.sc] > upper[v] + i.fr) { - upper[i.sc] = upper[v] + i.fr; - update = 1; + upper[1] = 0; + int update = 1; + for (int i = 0; i <= n; i++) { + update = 0; + for (int v = 1; v <= n; v++) { + if (upper[v] == INF) continue; + for (auto &i : adj[v]) { + if (upper[i.sc] > upper[v] + i.fr) { + upper[i.sc] = upper[v] + i.fr; + update = 1; + } + } } - } + if (!update) break; } - if (!update) break; - } - return !update; // Returns false <=> The graph has a negative cycle. + return !update; // Returns false <=> The graph has a negative cycle. } // 3. Floyd-Warshall Algorithm @@ -55,17 +55,17 @@ int bellmanFord() { int n, m; ll adj[1010][1010]; void floyd() { - for (int i = 0; i < 1010; i++) { - for (int j = 0; j < 1010; j++) { - adj[i][j] = (ll)1e18; + for (int i = 0; i < 1010; i++) { + for (int j = 0; j < 1010; j++) { + adj[i][j] = (ll)1e18; + } } - } - for (int i = 1; i <= n; i++) adj[i][i] = 0; - for (int k = 1; k <= n; k++) { - for (int u = 1; u <= n; u++) { - for (int v = 1; v <= n; v++) { - adj[u][v] = min(adj[u][v], adj[u][k] + adj[k][v]); - } + for (int i = 1; i <= n; i++) adj[i][i] = 0; + for (int k = 1; k <= n; k++) { + for (int u = 1; u <= n; u++) { + for (int v = 1; v <= n; v++) { + adj[u][v] = min(adj[u][v], adj[u][k] + adj[k][v]); + } + } } - } } \ No newline at end of file diff --git a/src/2-graph/euler_circuit.cpp b/src/2-graph/euler_circuit.cpp index 6d21658..b11757a 100644 --- a/src/2-graph/euler_circuit.cpp +++ b/src/2-graph/euler_circuit.cpp @@ -10,45 +10,45 @@ const int MAXV = 1010; int n, adj[MAXV][MAXV], nxt[MAXV]; vector eulerCircult; void input() { - cin >> n; - for (int i = 1; i <= n; i++) { - for (int j = 1; j <= n; j++) { - cin >> adj[i][j]; + cin >> n; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + cin >> adj[i][j]; + } } - } } int doesEulerCircuitExist() { - // If the degree of all nodes in the graph is even, then an euler circuit exists. - // Otherwise, the euler circuit does not exist. - // We can do similar way to determine the existence of euler path. - // If only two vertices have odd degree, than an eular path exists. Otherwise, the euler path does not exist. - for (int i = 1; i <= n; i++) { - int deg = 0; - for (int j = 1; j <= n; j++) { - deg += adj[i][j]; + // If the degree of all nodes in the graph is even, then an euler circuit exists. + // Otherwise, the euler circuit does not exist. + // We can do similar way to determine the existence of euler path. + // If only two vertices have odd degree, than an eular path exists. Otherwise, the euler path does not exist. + for (int i = 1; i <= n; i++) { + int deg = 0; + for (int j = 1; j <= n; j++) { + deg += adj[i][j]; + } + if (deg & 1) return 0; } - if (deg & 1) return 0; - } - return 1; + return 1; } void dfs(int now) { - for (int &x = nxt[now]; x <= n; x++) { - while (x <= n && adj[now][x]) { - adj[now][x]--; - adj[x][now]--; - dfs(x); + for (int &x = nxt[now]; x <= n; x++) { + while (x <= n && adj[now][x]) { + adj[now][x]--; + adj[x][now]--; + dfs(x); + } } - } - eulerCircult.push_back(now); + eulerCircult.push_back(now); } int main() { - input(); - if (!doesEulerCircuitExist()) { - cout << -1; - return 0; - } - for (int i = 1; i <= n; i++) nxt[i] = 1; - dfs(1); - for (auto i : eulerCircult) - cout << i << ' '; + input(); + if (!doesEulerCircuitExist()) { + cout << -1; + return 0; + } + for (int i = 1; i <= n; i++) nxt[i] = 1; + dfs(1); + for (auto i : eulerCircult) + cout << i << ' '; } \ No newline at end of file diff --git a/src/2-graph/kth_shortest_path.cpp b/src/2-graph/kth_shortest_path.cpp index b5d325f..dd99f4c 100644 --- a/src/2-graph/kth_shortest_path.cpp +++ b/src/2-graph/kth_shortest_path.cpp @@ -10,102 +10,102 @@ const ll INF = 1e18; // INF >= |E||X| (not need to be larg int n; vector> gph[MAXN], rgph[MAXN]; struct Lheap { - struct Node { - pll x; - int l, r, s; - Node(void) : x({0, 0}), l(0), r(0), s(0) {} - Node(pll x) : x(x), l(0), r(0), s(1) {} - } h[HSIZE]; - int cnt = 1; - int mk(pll x) { - h[cnt] = Node(x); - return cnt++; - } - void norm(int x) { - if (h[h[x].l].s < h[h[x].r].s) swap(h[x].l, h[x].r); - h[x].s = h[h[x].r].s + 1; - } - int mrge(int x, int y) { - if (!x || !y) return x ^ y; - if (h[x].x > h[y].x) swap(x, y); - int ret = mk(h[x].x); - h[ret].l = h[x].l; - h[ret].r = mrge(h[x].r, y); - norm(ret); - return ret; - } + struct Node { + pll x; + int l, r, s; + Node(void) : x({0, 0}), l(0), r(0), s(0) {} + Node(pll x) : x(x), l(0), r(0), s(1) {} + } h[HSIZE]; + int cnt = 1; + int mk(pll x) { + h[cnt] = Node(x); + return cnt++; + } + void norm(int x) { + if (h[h[x].l].s < h[h[x].r].s) swap(h[x].l, h[x].r); + h[x].s = h[h[x].r].s + 1; + } + int mrge(int x, int y) { + if (!x || !y) return x ^ y; + if (h[x].x > h[y].x) swap(x, y); + int ret = mk(h[x].x); + h[ret].l = h[x].l; + h[ret].r = mrge(h[x].r, y); + norm(ret); + return ret; + } } hp; void init(int _n) { - n = _n; - for (int i = 1; i <= n; ++i) gph[i].clear(); - for (int i = 1; i <= n; ++i) rgph[i].clear(); - hp.cnt = 1; + n = _n; + for (int i = 1; i <= n; ++i) gph[i].clear(); + for (int i = 1; i <= n; ++i) rgph[i].clear(); + hp.cnt = 1; } void add_edge(int u, int v, ll w) { - gph[u].push_back({w, v}); - rgph[v].push_back({w, u}); + gph[u].push_back({w, v}); + rgph[v].push_back({w, u}); } // return less than K elements if there is no such walk vector kth_walk(int s, int e, int K) { - vector nxt(n + 1); - vector top; - vector vst(n + 1); - vector dst(n + 1, INF); - dst[e] = 0; - typedef tuple tlii; - // if there is no negative edge - priority_queue, greater> Q; - Q.push({0, e, -1}); - while (!Q.empty()) { - auto [d, x, p] = Q.top(); - Q.pop(); - if (vst[x]) continue; - vst[x] = 1; - nxt[x] = p; - top.push_back(x); - for (auto [c, y] : rgph[x]) - if (!vst[y] && dst[y] > d + c) dst[y] = d + c, Q.push({d + c, y, x}); - } - // if there is negative edge - // nxt[e] = -1; - // for(int t = 0; t < n; ++t) { - // for(int x = 0; x < n; ++x) for(auto [c, y] : rgph[x]) if(dst[y] > dst[x] + c) - // dst[y] = dst[x] + c, nxt[y] = x; - // } - // // OR use SPFA - // vector ls[n]; - // for(int i = 0; i < n; ++i) if(nxt[i] != -1) ls[nxt[i]].push_back(i); - // queue Q; Q.push(e); - // while(Q.size()) { - // int x = Q.front(); Q.pop(); - // top.push_back(x); - // for(auto y : ls[x]) Q.push(y); - // } - if (dst[s] >= INF) return vector(); - vector chc(n + 1); - vector rt(n + 1); - for (auto x : top) - if (dst[x] < INF) { - if (nxt[x] != -1) rt[x] = rt[nxt[x]]; - for (auto [c, y] : gph[x]) - if (dst[y] < INF) { - if (!chc[x] && y == nxt[x] && dst[x] == c + dst[y]) { - chc[x] = 1; - continue; - } - rt[x] = hp.mrge(rt[x], hp.mk({c + dst[y] - dst[x], y})); + vector nxt(n + 1); + vector top; + vector vst(n + 1); + vector dst(n + 1, INF); + dst[e] = 0; + typedef tuple tlii; + // if there is no negative edge + priority_queue, greater> Q; + Q.push({0, e, -1}); + while (!Q.empty()) { + auto [d, x, p] = Q.top(); + Q.pop(); + if (vst[x]) continue; + vst[x] = 1; + nxt[x] = p; + top.push_back(x); + for (auto [c, y] : rgph[x]) + if (!vst[y] && dst[y] > d + c) dst[y] = d + c, Q.push({d + c, y, x}); + } + // if there is negative edge + // nxt[e] = -1; + // for(int t = 0; t < n; ++t) { + // for(int x = 0; x < n; ++x) for(auto [c, y] : rgph[x]) if(dst[y] > dst[x] + c) + // dst[y] = dst[x] + c, nxt[y] = x; + // } + // // OR use SPFA + // vector ls[n]; + // for(int i = 0; i < n; ++i) if(nxt[i] != -1) ls[nxt[i]].push_back(i); + // queue Q; Q.push(e); + // while(Q.size()) { + // int x = Q.front(); Q.pop(); + // top.push_back(x); + // for(auto y : ls[x]) Q.push(y); + // } + if (dst[s] >= INF) return vector(); + vector chc(n + 1); + vector rt(n + 1); + for (auto x : top) + if (dst[x] < INF) { + if (nxt[x] != -1) rt[x] = rt[nxt[x]]; + for (auto [c, y] : gph[x]) + if (dst[y] < INF) { + if (!chc[x] && y == nxt[x] && dst[x] == c + dst[y]) { + chc[x] = 1; + continue; + } + rt[x] = hp.mrge(rt[x], hp.mk({c + dst[y] - dst[x], y})); + } } + vector ret({dst[s]}); + priority_queue, greater> PQ; + if (rt[s]) PQ.push({hp.h[rt[s]].x.fr, rt[s]}); + while (sz(ret) < K && !PQ.empty()) { + auto [d, x] = PQ.top(); + PQ.pop(); + ret.push_back(dst[s] + d); + if (rt[hp.h[x].x.sc]) PQ.push({d + hp.h[rt[hp.h[x].x.sc]].x.fr, rt[hp.h[x].x.sc]}); + if (hp.h[x].l) PQ.push({d - hp.h[x].x.fr + hp.h[hp.h[x].l].x.fr, hp.h[x].l}); + if (hp.h[x].r) PQ.push({d - hp.h[x].x.fr + hp.h[hp.h[x].r].x.fr, hp.h[x].r}); } - vector ret({dst[s]}); - priority_queue, greater> PQ; - if (rt[s]) PQ.push({hp.h[rt[s]].x.fr, rt[s]}); - while (sz(ret) < K && !PQ.empty()) { - auto [d, x] = PQ.top(); - PQ.pop(); - ret.push_back(dst[s] + d); - if (rt[hp.h[x].x.sc]) PQ.push({d + hp.h[rt[hp.h[x].x.sc]].x.fr, rt[hp.h[x].x.sc]}); - if (hp.h[x].l) PQ.push({d - hp.h[x].x.fr + hp.h[hp.h[x].l].x.fr, hp.h[x].l}); - if (hp.h[x].r) PQ.push({d - hp.h[x].x.fr + hp.h[hp.h[x].r].x.fr, hp.h[x].r}); - } - return ret; + return ret; } \ No newline at end of file diff --git a/src/2-graph/offline_dynamic_connectivity.cpp b/src/2-graph/offline_dynamic_connectivity.cpp index 0572cc3..0974c9a 100644 --- a/src/2-graph/offline_dynamic_connectivity.cpp +++ b/src/2-graph/offline_dynamic_connectivity.cpp @@ -2,85 +2,85 @@ int flag; struct Seg { - vector> t; - void build(int n) { - for (flag = 1; flag < n; flag <<= 1); - t.resize(flag << 1); - } - void modify(int l, int r, pii val, int n = 1, int nl = 1, int nr = flag) { - if (r < nl || nr < l) return; - if (l <= nl && nr <= r) { - t[n].push_back(val); - return; + vector> t; + void build(int n) { + for (flag = 1; flag < n; flag <<= 1); + t.resize(flag << 1); + } + void modify(int l, int r, pii val, int n = 1, int nl = 1, int nr = flag) { + if (r < nl || nr < l) return; + if (l <= nl && nr <= r) { + t[n].push_back(val); + return; + } + int mid = (nl + nr) >> 1; + modify(l, r, val, n << 1, nl, mid); + modify(l, r, val, n << 1 | 1, mid + 1, nr); } - int mid = (nl + nr) >> 1; - modify(l, r, val, n << 1, nl, mid); - modify(l, r, val, n << 1 | 1, mid + 1, nr); - } } seg; struct UF { - vector par, siz, stk; - void build(int n) { - par.resize(n + 1); - iota(all(par), 0); - siz.resize(n + 1, 1); - } - int find(int x) { - if (par[x] == x) return x; - return find(par[x]); - } - void merge(int u, int v) { - u = find(u), v = find(v); - if (siz[u] < siz[v]) swap(u, v); - par[v] = u; - siz[u] += siz[v]; - stk.push_back(v); - } - void restore() { - assert(!stk.empty()); - int v = stk.back(); - stk.pop_back(); - siz[par[v]] -= siz[v]; - par[v] = v; - } + vector par, siz, stk; + void build(int n) { + par.resize(n + 1); + iota(all(par), 0); + siz.resize(n + 1, 1); + } + int find(int x) { + if (par[x] == x) return x; + return find(par[x]); + } + void merge(int u, int v) { + u = find(u), v = find(v); + if (siz[u] < siz[v]) swap(u, v); + par[v] = u; + siz[u] += siz[v]; + stk.push_back(v); + } + void restore() { + assert(!stk.empty()); + int v = stk.back(); + stk.pop_back(); + siz[par[v]] -= siz[v]; + par[v] = v; + } } uf; int n, m; map mp; pii qu[101010]; int ans[101010]; void input() { - cin >> n >> m; - uf.build(n); - seg.build(m); - for (int i = 1; i <= m; i++) { - int op, u, v; - cin >> op >> u >> v; - if (u > v) swap(u, v); + cin >> n >> m; + uf.build(n); + seg.build(m); + for (int i = 1; i <= m; i++) { + int op, u, v; + cin >> op >> u >> v; + if (u > v) swap(u, v); - if (op == 1) mp[{u, v}] = i; - if (op == 2) seg.modify(mp[{u, v}], i - 1, {u, v}), mp.erase({u, v}); - if (op == 3) qu[i] = {u, v}; - } - for (auto &[val, l] : mp) seg.modify(l, m, val); + if (op == 1) mp[{u, v}] = i; + if (op == 2) seg.modify(mp[{u, v}], i - 1, {u, v}), mp.erase({u, v}); + if (op == 3) qu[i] = {u, v}; + } + for (auto &[val, l] : mp) seg.modify(l, m, val); } void odc(int n = 1, int nl = 1, int nr = flag) { - int cnt = 0; - for (auto [u, v] : seg.t[n]) - if (uf.find(u) != uf.find(v)) uf.merge(u, v), cnt++; - if (nl == nr) { - if (nl <= m && qu[nl].fr) - ans[nl] = (uf.find(qu[nl].fr) == uf.find(qu[nl].sc)); + int cnt = 0; + for (auto [u, v] : seg.t[n]) + if (uf.find(u) != uf.find(v)) uf.merge(u, v), cnt++; + if (nl == nr) { + if (nl <= m && qu[nl].fr) + ans[nl] = (uf.find(qu[nl].fr) == uf.find(qu[nl].sc)); + while (cnt--) uf.restore(); + return; + } + int mid = (nl + nr) >> 1; + odc(n << 1, nl, mid); + odc(n << 1 | 1, mid + 1, nr); while (cnt--) uf.restore(); - return; - } - int mid = (nl + nr) >> 1; - odc(n << 1, nl, mid); - odc(n << 1 | 1, mid + 1, nr); - while (cnt--) uf.restore(); } int main() { - input(); - odc(); - for (int i = 1; i <= m; i++) - if (qu[i].fr) cout << ans[i] << '\n'; + input(); + odc(); + for (int i = 1; i <= m; i++) + if (qu[i].fr) cout << ans[i] << '\n'; } \ No newline at end of file diff --git a/src/2-graph/scc_2_sat.cpp b/src/2-graph/scc_2_sat.cpp index 5ac8f42..180e71c 100644 --- a/src/2-graph/scc_2_sat.cpp +++ b/src/2-graph/scc_2_sat.cpp @@ -11,56 +11,56 @@ int in[MAXV], out[MAXV], num, p[2 * MAXV]; int vi[MAXV], cnt; vector> scc; void input() { - cin >> n >> m; - for (int i = 0; i < m; i++) { - int u, v; - cin >> u >> v; - adj[u].push_back(v); - radj[v].push_back(u); - } + cin >> n >> m; + for (int i = 0; i < m; i++) { + int u, v; + cin >> u >> v; + adj[u].push_back(v); + radj[v].push_back(u); + } } void dfs(int v) { - in[v] = ++num; - for (auto &i : radj[v]) { - if (!in[i]) dfs(i); - } - out[v] = ++num; - p[num] = v; + in[v] = ++num; + for (auto &i : radj[v]) { + if (!in[i]) dfs(i); + } + out[v] = ++num; + p[num] = v; } void flood(int v) { - scc[cnt].push_back(v); - vi[v] = cnt; - for (auto &i : adj[v]) { - if (!vi[i]) flood(i); - } + scc[cnt].push_back(v); + vi[v] = cnt; + for (auto &i : adj[v]) { + if (!vi[i]) flood(i); + } } void kosaraju() { - for (int v = 1; v <= n; v++) { - if (!in[v]) dfs(v); - } - for (int v = 2 * n; v >= 1; v--) { - if (!p[v]) continue; - if (vi[p[v]]) continue; - cnt++; - scc.resize(cnt + 1); - flood(p[v]); - } + for (int v = 1; v <= n; v++) { + if (!in[v]) dfs(v); + } + for (int v = 2 * n; v >= 1; v--) { + if (!p[v]) continue; + if (vi[p[v]]) continue; + cnt++; + scc.resize(cnt + 1); + flood(p[v]); + } } void print() { - for (auto &i : scc) - sort(i.begin(), i.end()); - sort(scc.begin(), scc.end()); - cout << sz(scc) - 1 << '\n'; - for (int i = 1; i < sz(scc); i++) { - auto &arr = scc[i]; - for (auto &j : arr) cout << j << ' '; - cout << -1 << '\n'; - } + for (auto &i : scc) + sort(i.begin(), i.end()); + sort(scc.begin(), scc.end()); + cout << sz(scc) - 1 << '\n'; + for (int i = 1; i < sz(scc); i++) { + auto &arr = scc[i]; + for (auto &j : arr) cout << j << ' '; + cout << -1 << '\n'; + } } int main() { - input(); - kosaraju(); - print(); + input(); + kosaraju(); + print(); } // 2. SCC (Tarjan's strongly connected components algorithm) @@ -74,59 +74,59 @@ vector adj[MAXV]; stack stk; vector> SCC; void input() { - cin >> n >> m; - for (int i = 0; i < m; i++) { - int u, v; - cin >> u >> v; - adj[u].push_back(v); - } + cin >> n >> m; + for (int i = 0; i < m; i++) { + int u, v; + cin >> u >> v; + adj[u].push_back(v); + } } int dfs(int v) { - label[v] = labelCnt++; - stk.push(v); - int ret = label[v]; - for (int next : adj[v]) { - // Unvisited node. - if (label[next] == -1) ret = min(ret, dfs(next)); - // Visited but not yet classified as SCC. In other words, edge { v, next } is back edge. - else if (!finished[next]) ret = min(ret, label[next]); - } - // If there is no edge to the ancestor node among itself and its descendants, find scc. - if (ret == label[v]) { - vector vSCC; - while (1) { - int t = stk.top(); - stk.pop(); - vSCC.push_back(t); - SCCnum[t] = SCCcnt; - finished[t] = 1; - if (t == v) break; - } - SCC.push_back(vSCC); - SCCcnt++; - } - return ret; + label[v] = labelCnt++; + stk.push(v); + int ret = label[v]; + for (int next : adj[v]) { + // Unvisited node. + if (label[next] == -1) ret = min(ret, dfs(next)); + // Visited but not yet classified as SCC. In other words, edge { v, next } is back edge. + else if (!finished[next]) ret = min(ret, label[next]); + } + // If there is no edge to the ancestor node among itself and its descendants, find scc. + if (ret == label[v]) { + vector vSCC; + while (1) { + int t = stk.top(); + stk.pop(); + vSCC.push_back(t); + SCCnum[t] = SCCcnt; + finished[t] = 1; + if (t == v) break; + } + SCC.push_back(vSCC); + SCCcnt++; + } + return ret; } void getSCC() { - memset(label, -1, sizeof(label)); - for (int v = 1; v <= n; v++) - if (label[v] == -1) dfs(v); + memset(label, -1, sizeof(label)); + for (int v = 1; v <= n; v++) + if (label[v] == -1) dfs(v); } void print() { - for (auto &i : SCC) - sort(i.begin(), i.end()); - sort(SCC.begin(), SCC.end()); - cout << sz(SCC) << '\n'; - for (int i = 0; i < sz(SCC); i++) { - auto &arr = SCC[i]; - for (auto &j : arr) cout << j << ' '; - cout << -1 << '\n'; - } + for (auto &i : SCC) + sort(i.begin(), i.end()); + sort(SCC.begin(), SCC.end()); + cout << sz(SCC) << '\n'; + for (int i = 0; i < sz(SCC); i++) { + auto &arr = SCC[i]; + for (auto &j : arr) cout << j << ' '; + cout << -1 << '\n'; + } } int main() { - input(); - getSCC(); - print(); + input(); + getSCC(); + print(); } // 3. 2-SAT @@ -145,77 +145,77 @@ stack stk; pii p[MAXV]; int ans[MAXV / 2]; inline int inv(int x) { - // negative number -a indicates ¬a. - return (x > 0) ? 2 * (x - 1) : 2 * (-x - 1) + 1; + // negative number -a indicates ¬a. + return (x > 0) ? 2 * (x - 1) : 2 * (-x - 1) + 1; } void twoCnf(int a, int b) { - // (a ∨ b) iff (¬a → b) iff (¬b → a) - adj[inv(-a)].push_back(inv(b)); - adj[inv(-b)].push_back(inv(a)); + // (a ∨ b) iff (¬a → b) iff (¬b → a) + adj[inv(-a)].push_back(inv(b)); + adj[inv(-b)].push_back(inv(a)); } void input() { - cin >> n >> m; - for (int i = 0; i < m; i++) { - int a, b; - cin >> a >> b; - twoCnf(a, b); - } + cin >> n >> m; + for (int i = 0; i < m; i++) { + int a, b; + cin >> a >> b; + twoCnf(a, b); + } } int dfs(int now) { - int ret = dfsn[now] = ++dCnt; - stk.push(now); - for (int next : adj[now]) { - if (dfsn[next] == -1) ret = min(ret, dfs(next)); - else if (!finished[next]) ret = min(ret, dfsn[next]); - } - if (ret >= dfsn[now]) { - while (1) { - int t = stk.top(); - stk.pop(); - sNum[t] = sCnt; - finished[t] = 1; - if (t == now) break; - } - sCnt++; - } - return ret; + int ret = dfsn[now] = ++dCnt; + stk.push(now); + for (int next : adj[now]) { + if (dfsn[next] == -1) ret = min(ret, dfs(next)); + else if (!finished[next]) ret = min(ret, dfsn[next]); + } + if (ret >= dfsn[now]) { + while (1) { + int t = stk.top(); + stk.pop(); + sNum[t] = sCnt; + finished[t] = 1; + if (t == now) break; + } + sCnt++; + } + return ret; } int isSatisfiable() { - // determining satisfiability - int isS = 1; - for (int v = 0; v < 2 * n; v += 2) { - // if x and ¬x is in same scc, then the proposition is not satisfiable - if (sNum[v] == sNum[v + 1]) { - isS = 0; - break; + // determining satisfiability + int isS = 1; + for (int v = 0; v < 2 * n; v += 2) { + // if x and ¬x is in same scc, then the proposition is not satisfiable + if (sNum[v] == sNum[v + 1]) { + isS = 0; + break; + } } - } - return isS; + return isS; } void findValueOfEachVariable() { - // order of scc is the reverse of the topological sort - for (int v = 0; v < 2 * n; v++) { - p[v] = {sNum[v], v}; - } - sort(p, p + 2 * n); - // determining true/false of each variable - for (int i = 2 * n - 1; i >= 0; i--) { - int v = p[i].sc; - if (ans[v / 2 + 1] == -1) - ans[v / 2 + 1] = (v & 1) ? 1 : 0; - } - for (int v = 1; v <= n; v++) - cout << ans[v] << ' '; + // order of scc is the reverse of the topological sort + for (int v = 0; v < 2 * n; v++) { + p[v] = {sNum[v], v}; + } + sort(p, p + 2 * n); + // determining true/false of each variable + for (int i = 2 * n - 1; i >= 0; i--) { + int v = p[i].sc; + if (ans[v / 2 + 1] == -1) + ans[v / 2 + 1] = (v & 1) ? 1 : 0; + } + for (int v = 1; v <= n; v++) + cout << ans[v] << ' '; } int main() { - memset(dfsn, -1, sizeof(dfsn)); - memset(ans, -1, sizeof(ans)); - input(); - // finding scc - for (int v = 0; v < 2 * n; v++) - if (dfsn[v] == -1) dfs(v); - if (isSatisfiable()) { - cout << 1 << '\n'; - findValueOfEachVariable(); - } else cout << 0; + memset(dfsn, -1, sizeof(dfsn)); + memset(ans, -1, sizeof(ans)); + input(); + // finding scc + for (int v = 0; v < 2 * n; v++) + if (dfsn[v] == -1) dfs(v); + if (isSatisfiable()) { + cout << 1 << '\n'; + findValueOfEachVariable(); + } else cout << 0; } \ No newline at end of file diff --git a/src/2-graph/tree_cd.cpp b/src/2-graph/tree_cd.cpp index 9808f66..b6b346f 100644 --- a/src/2-graph/tree_cd.cpp +++ b/src/2-graph/tree_cd.cpp @@ -13,27 +13,27 @@ int siz[MAXN], cdpar[MAXN]; bool used[MAXN]; int getSize(int now, int prv) { - siz[now] = 1; - for (auto i : adj[now]) { - if (used[i] || prv == i) continue; - siz[now] += getSize(i, now); - } - return siz[now]; + siz[now] = 1; + for (auto i : adj[now]) { + if (used[i] || prv == i) continue; + siz[now] += getSize(i, now); + } + return siz[now]; } int getCent(int now, int prv, int mxsiz) { - for (auto &i : adj[now]) { - if (used[i] || i == prv) continue; - if (siz[i] > mxsiz / 2) return getCent(i, now, mxsiz); - } - return now; + for (auto &i : adj[now]) { + if (used[i] || i == prv) continue; + if (siz[i] > mxsiz / 2) return getCent(i, now, mxsiz); + } + return now; } void cd(int now, int prv) { - int mxsiz = getSize(now, prv); - int cent = getCent(now, prv, mxsiz); - cdpar[cent] = prv; - cdchd[prv].push_back(cent); - used[cent] = 1; - for (auto i : adj[cent]) - if (!used[i]) cd(i, cent); + int mxsiz = getSize(now, prv); + int cent = getCent(now, prv, mxsiz); + cdpar[cent] = prv; + cdchd[prv].push_back(cent); + used[cent] = 1; + for (auto i : adj[cent]) + if (!used[i]) cd(i, cent); } } // namespace cd \ No newline at end of file diff --git a/src/2-graph/tree_composition.cpp b/src/2-graph/tree_composition.cpp index b36433f..eb437e5 100644 --- a/src/2-graph/tree_composition.cpp +++ b/src/2-graph/tree_composition.cpp @@ -10,77 +10,77 @@ ll dp[MAXN]; vector cpchd[MAXN]; int cppar[MAXN]; void input() { - cin >> n >> q; - for (int i = 2; i <= n; i++) { - cin >> par[i][0]; - chd[par[i][0]].push_back(i); - } + cin >> n >> q; + for (int i = 2; i <= n; i++) { + cin >> par[i][0]; + chd[par[i][0]].push_back(i); + } } void dfs(int v, int prv) { - in[v] = ++p; - dep[v] = 1 + dep[prv]; - for (auto &i : chd[v]) - if (i != prv) dfs(i, v); + in[v] = ++p; + dep[v] = 1 + dep[prv]; + for (auto &i : chd[v]) + if (i != prv) dfs(i, v); } void build_sparse_table() { - for (int d = 0; d + 1 <= MAXD; d++) - for (int v = 1; v <= n; v++) - par[v][d + 1] = par[par[v][d]][d]; + for (int d = 0; d + 1 <= MAXD; d++) + for (int v = 1; v <= n; v++) + par[v][d + 1] = par[par[v][d]][d]; } int lca(int u, int v) { - if (dep[u] > dep[v]) swap(u, v); - int diff = dep[v] - dep[u]; - for (int i = 0; i <= MAXD; i++) { - if (diff & (1 << i)) { - v = par[v][i]; + if (dep[u] > dep[v]) swap(u, v); + int diff = dep[v] - dep[u]; + for (int i = 0; i <= MAXD; i++) { + if (diff & (1 << i)) { + v = par[v][i]; + } } - } - if (u == v) return u; - for (int i = MAXD; i >= 0; i--) { - if (par[u][i] ^ par[v][i]) { - u = par[u][i]; - v = par[v][i]; + if (u == v) return u; + for (int i = MAXD; i >= 0; i--) { + if (par[u][i] ^ par[v][i]) { + u = par[u][i]; + v = par[v][i]; + } } - } - return par[u][0]; + return par[u][0]; } int main() { - input(); - dfs(1, 0); - build_sparse_table(); - while (q--) { - int k; - cin >> k; - vector vs(k); - for (auto &i : vs) cin >> i; - for (auto &i : vs) dp[i] = 1; - sort(all(vs), [&](int p1, int p2) { - return in[p1] < in[p2]; - }); - for (int i = 0; i + 1 < k; i++) { - vs.push_back(lca(vs[i], vs[i + 1])); - } - sort(all(vs), [&](int p1, int p2) { - return in[p1] < in[p2]; - }); - vs.erase(unique(all(vs)), vs.end()); - for (int i = 0; i + 1 < sz(vs); i++) { - int u = vs[i], v = vs[i + 1]; - int l = lca(u, v); - cpchd[l].push_back(v); - } - ll ans = 0; - for (int i = sz(vs) - 1; i >= 0; i--) { - int p = vs[i]; - for (auto &v : cpchd[p]) { - ans += dp[p] * dp[v] * (dep[p] - 1); - dp[p] += dp[v]; - } - } - for (auto &i : vs) { - dp[i] = 0; - cpchd[i].clear(); + input(); + dfs(1, 0); + build_sparse_table(); + while (q--) { + int k; + cin >> k; + vector vs(k); + for (auto &i : vs) cin >> i; + for (auto &i : vs) dp[i] = 1; + sort(all(vs), [&](int p1, int p2) { + return in[p1] < in[p2]; + }); + for (int i = 0; i + 1 < k; i++) { + vs.push_back(lca(vs[i], vs[i + 1])); + } + sort(all(vs), [&](int p1, int p2) { + return in[p1] < in[p2]; + }); + vs.erase(unique(all(vs)), vs.end()); + for (int i = 0; i + 1 < sz(vs); i++) { + int u = vs[i], v = vs[i + 1]; + int l = lca(u, v); + cpchd[l].push_back(v); + } + ll ans = 0; + for (int i = sz(vs) - 1; i >= 0; i--) { + int p = vs[i]; + for (auto &v : cpchd[p]) { + ans += dp[p] * dp[v] * (dep[p] - 1); + dp[p] += dp[v]; + } + } + for (auto &i : vs) { + dp[i] = 0; + cpchd[i].clear(); + } + cout << ans << '\n'; } - cout << ans << '\n'; - } } \ No newline at end of file diff --git a/src/2-graph/tree_exchange_argument.cpp b/src/2-graph/tree_exchange_argument.cpp index e30c6fe..4349c7f 100644 --- a/src/2-graph/tree_exchange_argument.cpp +++ b/src/2-graph/tree_exchange_argument.cpp @@ -2,72 +2,72 @@ const int MAXN = 303030; struct UF { - vector uf; - vector cw, w, t; - void build(int n) { - uf.resize(n + 1, -1); - cw.resize(n + 1); - iota(all(cw), 0); - w.resize(n + 1); - iota(all(w), 0); - t.resize(n + 1, 1); - } - int find(int x) { - if (uf[x] < 0) return x; - return uf[x] = find(uf[x]); - } - void merge(int u, int v) { - // int U = find(u), V = find(v); - // assert(U != V); - uf[v] = u; - cw[u] += t[u] * w[v] + cw[v]; - w[u] += w[v]; - t[u] += t[v]; - } + vector uf; + vector cw, w, t; + void build(int n) { + uf.resize(n + 1, -1); + cw.resize(n + 1); + iota(all(cw), 0); + w.resize(n + 1); + iota(all(w), 0); + t.resize(n + 1, 1); + } + int find(int x) { + if (uf[x] < 0) return x; + return uf[x] = find(uf[x]); + } + void merge(int u, int v) { + // int U = find(u), V = find(v); + // assert(U != V); + uf[v] = u; + cw[u] += t[u] * w[v] + cw[v]; + w[u] += w[v]; + t[u] += t[v]; + } } uf; struct Node { - ll cw, w, t; - int v; - bool operator<(const Node &o) const { - return w * o.t > o.w * t; - } + ll cw, w, t; + int v; + bool operator<(const Node &o) const { + return w * o.t > o.w * t; + } }; int n, ro; vector adj[MAXN]; int par[MAXN]; void input() { - cin >> n >> ro; - uf.build(n); - for (int i = 0; i < n - 1; i++) { - int u, v; - cin >> u >> v; - adj[u].push_back(v); - adj[v].push_back(u); - } + cin >> n >> ro; + uf.build(n); + for (int i = 0; i < n - 1; i++) { + int u, v; + cin >> u >> v; + adj[u].push_back(v); + adj[v].push_back(u); + } } void dfs(int v, int prv) { - par[v] = prv; - for (auto &i : adj[v]) { - if (i != prv) dfs(i, v); - } + par[v] = prv; + for (auto &i : adj[v]) { + if (i != prv) dfs(i, v); + } } void solve() { - priority_queue pq; - for (int v = 1; v <= n; v++) - if (v != ro) pq.push({uf.cw[v], uf.w[v], uf.t[v], v}); - while (!pq.empty()) { - auto [cw, w, t, v] = pq.top(); - pq.pop(); - v = uf.find(v); - if (w != uf.w[v]) continue; - int p = uf.find(par[v]); - uf.merge(p, v); - if (p != ro) pq.push({uf.cw[p], uf.w[p], uf.t[p], p}); - } + priority_queue pq; + for (int v = 1; v <= n; v++) + if (v != ro) pq.push({uf.cw[v], uf.w[v], uf.t[v], v}); + while (!pq.empty()) { + auto [cw, w, t, v] = pq.top(); + pq.pop(); + v = uf.find(v); + if (w != uf.w[v]) continue; + int p = uf.find(par[v]); + uf.merge(p, v); + if (p != ro) pq.push({uf.cw[p], uf.w[p], uf.t[p], p}); + } } int main() { - input(); - dfs(ro, 0); - solve(); - cout << uf.cw[ro]; + input(); + dfs(ro, 0); + solve(); + cout << uf.cw[ro]; } \ No newline at end of file diff --git a/src/2-graph/tree_hld.cpp b/src/2-graph/tree_hld.cpp index ec0145c..cf6db78 100644 --- a/src/2-graph/tree_hld.cpp +++ b/src/2-graph/tree_hld.cpp @@ -5,20 +5,20 @@ const int MAXN = 202020; int flag; // array size struct Seg { // 1-indexed - vector t; - void build(int n) { - for (flag = 1; flag < n; flag <<= 1); - t.resize(flag << 1); - } - void modify(int p, ll value) { // set value at position p - for (t[p += flag - 1] = value; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1]; - } - ll query(int l, int r, int n = 1, int nl = 1, int nr = flag) { // sum on interval [l, r] - if (r < nl || nr < l) return 0; - if (l <= nl && nr <= r) return t[n]; - int mid = (nl + nr) / 2; - return query(l, r, n << 1, nl, mid) + query(l, r, n << 1 | 1, mid + 1, nr); - } + vector t; + void build(int n) { + for (flag = 1; flag < n; flag <<= 1); + t.resize(flag << 1); + } + void modify(int p, ll value) { // set value at position p + for (t[p += flag - 1] = value; p > 1; p >>= 1) t[p >> 1] = t[p] + t[p ^ 1]; + } + ll query(int l, int r, int n = 1, int nl = 1, int nr = flag) { // sum on interval [l, r] + if (r < nl || nr < l) return 0; + if (l <= nl && nr <= r) return t[n]; + int mid = (nl + nr) / 2; + return query(l, r, n << 1, nl, mid) + query(l, r, n << 1 | 1, mid + 1, nr); + } } seg; int n; @@ -27,47 +27,47 @@ int siz[MAXN], dep[MAXN], par[MAXN]; int top[MAXN], in[MAXN], pv; void dfs(int v, int prv) { - for (auto &i : adj[v]) { - if (i == prv) continue; - g[v].push_back(i); - dfs(i, v); - } + for (auto &i : adj[v]) { + if (i == prv) continue; + g[v].push_back(i); + dfs(i, v); + } } int dfs1(int v) { - siz[v] = 1; - for (auto &i : g[v]) { - dep[i] = dep[v] + 1, par[i] = v; - siz[v] += dfs1(i); - if (siz[i] > siz[g[v][0]]) swap(i, g[v][0]); - } - return siz[v]; + siz[v] = 1; + for (auto &i : g[v]) { + dep[i] = dep[v] + 1, par[i] = v; + siz[v] += dfs1(i); + if (siz[i] > siz[g[v][0]]) swap(i, g[v][0]); + } + return siz[v]; } void dfs2(int v) { - in[v] = ++pv; - for (auto &i : g[v]) { - top[i] = (i == g[v][0] ? top[v] : i); - dfs2(i); - } + in[v] = ++pv; + for (auto &i : g[v]) { + top[i] = (i == g[v][0] ? top[v] : i); + dfs2(i); + } } void modify(int v, ll value) { - seg.modify(in[v], value); + seg.modify(in[v], value); } ll query(int u, int v) { - ll ret = 0; - while (top[u] ^ top[v]) { - if (dep[top[u]] < dep[top[v]]) swap(u, v); - int st = top[u]; - ret += seg.query(in[st], in[u]); - u = par[st]; - } - if (dep[u] > dep[v]) swap(u, v); - return ret += seg.query(in[u], in[v]); + ll ret = 0; + while (top[u] ^ top[v]) { + if (dep[top[u]] < dep[top[v]]) swap(u, v); + int st = top[u]; + ret += seg.query(in[st], in[u]); + u = par[st]; + } + if (dep[u] > dep[v]) swap(u, v); + return ret += seg.query(in[u], in[v]); } void hld() { - dfs(1, 0); - top[1] = 1; - dfs1(1); - dfs2(1); - seg.build(n); + dfs(1, 0); + top[1] = 1; + dfs1(1); + dfs2(1); + seg.build(n); } } // namespace hld \ No newline at end of file diff --git a/src/2-graph/tree_lca_sparse_table.cpp b/src/2-graph/tree_lca_sparse_table.cpp index b3901f0..f4b54b8 100644 --- a/src/2-graph/tree_lca_sparse_table.cpp +++ b/src/2-graph/tree_lca_sparse_table.cpp @@ -7,32 +7,32 @@ int n, dep[MAXN], par[MAXN][MAXD + 1]; vector adj[MAXN]; void dfs(int now, int prv) { - par[now][0] = prv; - dep[now] = dep[prv] + 1; - for (auto i : adj[now]) { - if (i == prv) continue; - dfs(i, now); - } + par[now][0] = prv; + dep[now] = dep[prv] + 1; + for (auto i : adj[now]) { + if (i == prv) continue; + dfs(i, now); + } } void buildSparseTable() { - for (int i = 1; i <= MAXD; i++) { - for (int v = 1; v <= n; v++) { - par[v][i] = par[par[v][i - 1]][i - 1]; + for (int i = 1; i <= MAXD; i++) { + for (int v = 1; v <= n; v++) { + par[v][i] = par[par[v][i - 1]][i - 1]; + } } - } } int lca(int u, int v) { - if (dep[u] < dep[v]) swap(u, v); - int diff = dep[u] - dep[v]; - for (int i = MAXD; i >= 0; i--) - if (diff & (1 << i)) u = par[u][i]; - if (u == v) return u; - for (int i = MAXD; i >= 0; i--) { - if (par[u][i] ^ par[v][i]) { - u = par[u][i]; - v = par[v][i]; + if (dep[u] < dep[v]) swap(u, v); + int diff = dep[u] - dep[v]; + for (int i = MAXD; i >= 0; i--) + if (diff & (1 << i)) u = par[u][i]; + if (u == v) return u; + for (int i = MAXD; i >= 0; i--) { + if (par[u][i] ^ par[v][i]) { + u = par[u][i]; + v = par[v][i]; + } } - } - return par[u][0]; + return par[u][0]; } } // namespace sparse_table \ No newline at end of file diff --git a/src/3-optimizations/flow.cpp b/src/3-optimizations/flow.cpp index 8256d65..fdab9d1 100644 --- a/src/3-optimizations/flow.cpp +++ b/src/3-optimizations/flow.cpp @@ -13,94 +13,94 @@ constexpr ll INF = (1LL << 62); // constraint: cap >= 0 // usage: dinic mf(n); mf.add_edge(u, v, cap); ll f = mf.max_flow(s, t); struct dinic { - struct edge { - int to, rev; - ll cap; - }; - struct edge_ref { - int u, idx; - }; - - int n; - vector> g; - vector level, work; - - dinic(int n = 0) { init(n); } - - void init(int n_) { - n = n_; - g.assign(n, {}); - } - - edge_ref add_edge(int u, int v, ll cap) { - // goal: add forward + reverse edge - edge a{v, (int)g[v].size(), cap}; - edge b{u, (int)g[u].size(), 0}; - g[u].push_back(a); - g[v].push_back(b); - return {u, (int)g[u].size() - 1}; - } - - ll edge_flow(edge_ref e) const { - // goal: current flow on original edge - const edge &ed = g[e.u][e.idx]; - return g[ed.to][ed.rev].cap; - } - - void clear_edge(edge_ref e) { - // goal: remove edge from residual graph - edge &ed = g[e.u][e.idx]; - edge &rev = g[ed.to][ed.rev]; - ed.cap = 0; - rev.cap = 0; - } - - bool bfs(int s, int t) { - // goal: build level graph - level.assign(n, -1); - queue q; - level[s] = 0; - q.push(s); - while (!q.empty()) { - int v = q.front(); - q.pop(); - for (const auto &e : g[v]) { - if (e.cap == 0 || level[e.to] != -1) continue; - level[e.to] = level[v] + 1; - q.push(e.to); - } + struct edge { + int to, rev; + ll cap; + }; + struct edge_ref { + int u, idx; + }; + + int n; + vector> g; + vector level, work; + + dinic(int n = 0) { init(n); } + + void init(int n_) { + n = n_; + g.assign(n, {}); } - return level[t] != -1; - } - - ll dfs(int v, int t, ll f) { - if (v == t || f == 0) return f; - for (int &i = work[v]; i < (int)g[v].size(); i++) { - edge &e = g[v][i]; - if (e.cap == 0 || level[e.to] != level[v] + 1) continue; - // invariant: level strictly increases along augmenting path - ll pushed = dfs(e.to, t, min(f, e.cap)); - if (pushed == 0) continue; - e.cap -= pushed; - g[e.to][e.rev].cap += pushed; - return pushed; + + edge_ref add_edge(int u, int v, ll cap) { + // goal: add forward + reverse edge + edge a{v, (int)g[v].size(), cap}; + edge b{u, (int)g[u].size(), 0}; + g[u].push_back(a); + g[v].push_back(b); + return {u, (int)g[u].size() - 1}; } - return 0; - } - - ll max_flow(int s, int t, ll limit = INF) { - if (s == t) return 0; // edge: no flow needed - ll flow = 0; - while (flow < limit && bfs(s, t)) { - work.assign(n, 0); - while (flow < limit) { - ll pushed = dfs(s, t, limit - flow); - if (pushed == 0) break; - flow += pushed; - } + + ll edge_flow(edge_ref e) const { + // goal: current flow on original edge + const edge &ed = g[e.u][e.idx]; + return g[ed.to][ed.rev].cap; + } + + void clear_edge(edge_ref e) { + // goal: remove edge from residual graph + edge &ed = g[e.u][e.idx]; + edge &rev = g[ed.to][ed.rev]; + ed.cap = 0; + rev.cap = 0; + } + + bool bfs(int s, int t) { + // goal: build level graph + level.assign(n, -1); + queue q; + level[s] = 0; + q.push(s); + while (!q.empty()) { + int v = q.front(); + q.pop(); + for (const auto &e : g[v]) { + if (e.cap == 0 || level[e.to] != -1) continue; + level[e.to] = level[v] + 1; + q.push(e.to); + } + } + return level[t] != -1; + } + + ll dfs(int v, int t, ll f) { + if (v == t || f == 0) return f; + for (int &i = work[v]; i < (int)g[v].size(); i++) { + edge &e = g[v][i]; + if (e.cap == 0 || level[e.to] != level[v] + 1) continue; + // invariant: level strictly increases along augmenting path + ll pushed = dfs(e.to, t, min(f, e.cap)); + if (pushed == 0) continue; + e.cap -= pushed; + g[e.to][e.rev].cap += pushed; + return pushed; + } + return 0; + } + + ll max_flow(int s, int t, ll limit = INF) { + if (s == t) return 0; // edge: no flow needed + ll flow = 0; + while (flow < limit && bfs(s, t)) { + work.assign(n, 0); + while (flow < limit) { + ll pushed = dfs(s, t, limit - flow); + if (pushed == 0) break; + flow += pushed; + } + } + return flow; } - return flow; - } }; // hk bipartite matching (0-based). @@ -109,78 +109,78 @@ struct dinic { // constraint: left [0..n_l-1], right [0..n_r-1] // usage: hk bm(n_l, n_r); bm.add_edge(l, r); int m = bm.max_matching(); struct hk { - int n_l, n_r; - vector> g; - vector dist, match_l, match_r; - - hk(int n_l_ = 0, int n_r_ = 0) { init(n_l_, n_r_); } - - void init(int n_l_, int n_r_) { - n_l = n_l_; - n_r = n_r_; - g.assign(n_l, {}); - dist.assign(n_l, 0); - match_l.assign(n_l, -1); - match_r.assign(n_r, -1); - } - - void add_edge(int l, int r) { - // goal: add edge from left to right - g[l].push_back(r); - } - - bool bfs() { - // goal: build layers for shortest augmenting paths - queue q; - fill(dist.begin(), dist.end(), -1); - for (int i = 0; i < n_l; i++) { - if (match_l[i] == -1) { - dist[i] = 0; - q.push(i); - } + int n_l, n_r; + vector> g; + vector dist, match_l, match_r; + + hk(int n_l_ = 0, int n_r_ = 0) { init(n_l_, n_r_); } + + void init(int n_l_, int n_r_) { + n_l = n_l_; + n_r = n_r_; + g.assign(n_l, {}); + dist.assign(n_l, 0); + match_l.assign(n_l, -1); + match_r.assign(n_r, -1); + } + + void add_edge(int l, int r) { + // goal: add edge from left to right + g[l].push_back(r); } - bool found = false; - while (!q.empty()) { - int v = q.front(); - q.pop(); - for (int r : g[v]) { - int u = match_r[r]; - if (u == -1) { - found = true; - } else if (dist[u] == -1) { - dist[u] = dist[v] + 1; - q.push(u); + + bool bfs() { + // goal: build layers for shortest augmenting paths + queue q; + fill(dist.begin(), dist.end(), -1); + for (int i = 0; i < n_l; i++) { + if (match_l[i] == -1) { + dist[i] = 0; + q.push(i); + } + } + bool found = false; + while (!q.empty()) { + int v = q.front(); + q.pop(); + for (int r : g[v]) { + int u = match_r[r]; + if (u == -1) { + found = true; + } else if (dist[u] == -1) { + dist[u] = dist[v] + 1; + q.push(u); + } + } } - } + return found; } - return found; - } - - bool dfs(int v) { - for (int r : g[v]) { - int u = match_r[r]; - if (u == -1 || (dist[u] == dist[v] + 1 && dfs(u))) { - match_l[v] = r; - match_r[r] = v; - return true; - } + + bool dfs(int v) { + for (int r : g[v]) { + int u = match_r[r]; + if (u == -1 || (dist[u] == dist[v] + 1 && dfs(u))) { + match_l[v] = r; + match_r[r] = v; + return true; + } + } + dist[v] = -1; + return false; } - dist[v] = -1; - return false; - } - - int max_matching() { - // goal: compute maximum matching size - fill(match_l.begin(), match_l.end(), -1); - fill(match_r.begin(), match_r.end(), -1); - int match = 0; - while (bfs()) { - for (int i = 0; i < n_l; i++) { - if (match_l[i] == -1 && dfs(i)) match++; - } + + int max_matching() { + // goal: compute maximum matching size + fill(match_l.begin(), match_l.end(), -1); + fill(match_r.begin(), match_r.end(), -1); + int match = 0; + while (bfs()) { + for (int i = 0; i < n_l; i++) { + if (match_l[i] == -1 && dfs(i)) match++; + } + } + return match; } - return match; - } }; // mcmf min-cost max-flow (0-based). @@ -190,121 +190,121 @@ struct hk { // usage: mcmf mf(n); mf.add_edge(u, v, cap, cost); pll r = mf.min_cost_max_flow(s, t); // usage: init_pot = false if all costs >= 0 (faster) struct mcmf { - struct edge { - int to, rev; - ll cap, cost; - }; - struct edge_ref { - int u, idx; - }; - - int n; - vector> g; - - mcmf(int n = 0) { init(n); } - - void init(int n_) { - n = n_; - g.assign(n, {}); - } - - edge_ref add_edge(int u, int v, ll cap, ll cost) { - // goal: add forward + reverse edge with costs - edge a{v, (int)g[v].size(), cap, cost}; - edge b{u, (int)g[u].size(), 0, -cost}; - g[u].push_back(a); - g[v].push_back(b); - return {u, (int)g[u].size() - 1}; - } - - ll edge_flow(edge_ref e) const { - // goal: current flow on original edge - const edge &ed = g[e.u][e.idx]; - return g[ed.to][ed.rev].cap; - } - - void clear_edge(edge_ref e) { - // goal: remove edge from residual graph - edge &ed = g[e.u][e.idx]; - edge &rev = g[ed.to][ed.rev]; - ed.cap = 0; - rev.cap = 0; - } - - pll min_cost_max_flow(int s, int t, ll max_f = INF, bool init_pot = true) { - ll flow = 0, cost = 0; - vector pot(n, 0), dist(n); - vector pv(n), pe(n); - - if (init_pot) { - // goal: initial potentials for negative costs - vector d(n, INF); - vector in_q(n, 0); - queue q; - d[s] = 0; - q.push(s); - in_q[s] = 1; - while (!q.empty()) { - int v = q.front(); - q.pop(); - in_q[v] = 0; - for (const auto &e : g[v]) { - if (e.cap == 0) continue; - if (d[v] + e.cost < d[e.to]) { - d[e.to] = d[v] + e.cost; - if (!in_q[e.to]) { - in_q[e.to] = 1; - q.push(e.to); + struct edge { + int to, rev; + ll cap, cost; + }; + struct edge_ref { + int u, idx; + }; + + int n; + vector> g; + + mcmf(int n = 0) { init(n); } + + void init(int n_) { + n = n_; + g.assign(n, {}); + } + + edge_ref add_edge(int u, int v, ll cap, ll cost) { + // goal: add forward + reverse edge with costs + edge a{v, (int)g[v].size(), cap, cost}; + edge b{u, (int)g[u].size(), 0, -cost}; + g[u].push_back(a); + g[v].push_back(b); + return {u, (int)g[u].size() - 1}; + } + + ll edge_flow(edge_ref e) const { + // goal: current flow on original edge + const edge &ed = g[e.u][e.idx]; + return g[ed.to][ed.rev].cap; + } + + void clear_edge(edge_ref e) { + // goal: remove edge from residual graph + edge &ed = g[e.u][e.idx]; + edge &rev = g[ed.to][ed.rev]; + ed.cap = 0; + rev.cap = 0; + } + + pll min_cost_max_flow(int s, int t, ll max_f = INF, bool init_pot = true) { + ll flow = 0, cost = 0; + vector pot(n, 0), dist(n); + vector pv(n), pe(n); + + if (init_pot) { + // goal: initial potentials for negative costs + vector d(n, INF); + vector in_q(n, 0); + queue q; + d[s] = 0; + q.push(s); + in_q[s] = 1; + while (!q.empty()) { + int v = q.front(); + q.pop(); + in_q[v] = 0; + for (const auto &e : g[v]) { + if (e.cap == 0) continue; + if (d[v] + e.cost < d[e.to]) { + d[e.to] = d[v] + e.cost; + if (!in_q[e.to]) { + in_q[e.to] = 1; + q.push(e.to); + } + } + } } - } + for (int i = 0; i < n; i++) + if (d[i] < INF) pot[i] = d[i]; } - } - for (int i = 0; i < n; i++) - if (d[i] < INF) pot[i] = d[i]; - } - while (flow < max_f) { - // goal: shortest path in reduced costs - fill(dist.begin(), dist.end(), INF); - dist[s] = 0; - priority_queue, vector>, greater>> pq; - pq.push({0, s}); - while (!pq.empty()) { - auto [d, v] = pq.top(); - pq.pop(); - if (d != dist[v]) continue; - for (int i = 0; i < (int)g[v].size(); i++) { - const auto &e = g[v][i]; - if (e.cap == 0) continue; - ll nd = d + e.cost + pot[v] - pot[e.to]; - if (nd < dist[e.to]) { - dist[e.to] = nd; - pv[e.to] = v; - pe[e.to] = i; - pq.push({nd, e.to}); - } + while (flow < max_f) { + // goal: shortest path in reduced costs + fill(dist.begin(), dist.end(), INF); + dist[s] = 0; + priority_queue, vector>, greater>> pq; + pq.push({0, s}); + while (!pq.empty()) { + auto [d, v] = pq.top(); + pq.pop(); + if (d != dist[v]) continue; + for (int i = 0; i < (int)g[v].size(); i++) { + const auto &e = g[v][i]; + if (e.cap == 0) continue; + ll nd = d + e.cost + pot[v] - pot[e.to]; + if (nd < dist[e.to]) { + dist[e.to] = nd; + pv[e.to] = v; + pe[e.to] = i; + pq.push({nd, e.to}); + } + } + } + if (dist[t] == INF) break; // edge: no more augmenting paths + for (int i = 0; i < n; i++) + if (dist[i] < INF) pot[i] += dist[i]; + + ll add = max_f - flow; + for (int v = t; v != s; v = pv[v]) { + const auto &e = g[pv[v]][pe[v]]; + add = min(add, e.cap); + } + for (int v = t; v != s; v = pv[v]) { + auto &e = g[pv[v]][pe[v]]; + e.cap -= add; + g[v][e.rev].cap += add; + cost += add * e.cost; + } + flow += add; } - } - if (dist[t] == INF) break; // edge: no more augmenting paths - for (int i = 0; i < n; i++) - if (dist[i] < INF) pot[i] += dist[i]; - - ll add = max_f - flow; - for (int v = t; v != s; v = pv[v]) { - const auto &e = g[pv[v]][pe[v]]; - add = min(add, e.cap); - } - for (int v = t; v != s; v = pv[v]) { - auto &e = g[pv[v]][pe[v]]; - e.cap -= add; - g[v][e.rev].cap += add; - cost += add * e.cost; - } - flow += add; - } - return {flow, cost}; - } + return {flow, cost}; + } }; // lr_dinic (0-based). @@ -313,82 +313,82 @@ struct mcmf { // constraint: 0 <= lo <= hi, single-use (call init(n) to reuse) // usage: lr_dinic f(n); int id = f.add_edge(u, v, lo, hi); auto [ok, v] = f.max_flow(s, t); struct lr_dinic { - struct edge_info { - dinic::edge_ref ref; - ll lo; - }; - - int n; - dinic mf; - vector demand; - vector edges; - - lr_dinic(int n = 0) { init(n); } - - void init(int n_) { - n = n_; - mf.init(n + 2); - demand.assign(n, 0); - edges.clear(); - } - - int add_edge(int u, int v, ll lo, ll hi) { - // goal: store lower bounds via node demands - demand[u] -= lo; - demand[v] += lo; - edges.push_back({mf.add_edge(u, v, hi - lo), lo}); - return (int)edges.size() - 1; - } - - ll edge_flow(int id) const { - // goal: actual flow with lower bound restored - return edges[id].lo + mf.edge_flow(edges[id].ref); - } - - ll add_demands(vector &aux) { - // goal: connect ss/tt for feasible circulation - ll total = 0; - int ss = n, tt = n + 1; - for (int i = 0; i < n; i++) { - if (demand[i] > 0) { - aux.push_back(mf.add_edge(ss, i, demand[i])); - total += demand[i]; - } else if (demand[i] < 0) { - aux.push_back(mf.add_edge(i, tt, -demand[i])); - } + struct edge_info { + dinic::edge_ref ref; + ll lo; + }; + + int n; + dinic mf; + vector demand; + vector edges; + + lr_dinic(int n = 0) { init(n); } + + void init(int n_) { + n = n_; + mf.init(n + 2); + demand.assign(n, 0); + edges.clear(); + } + + int add_edge(int u, int v, ll lo, ll hi) { + // goal: store lower bounds via node demands + demand[u] -= lo; + demand[v] += lo; + edges.push_back({mf.add_edge(u, v, hi - lo), lo}); + return (int)edges.size() - 1; + } + + ll edge_flow(int id) const { + // goal: actual flow with lower bound restored + return edges[id].lo + mf.edge_flow(edges[id].ref); + } + + ll add_demands(vector &aux) { + // goal: connect ss/tt for feasible circulation + ll total = 0; + int ss = n, tt = n + 1; + for (int i = 0; i < n; i++) { + if (demand[i] > 0) { + aux.push_back(mf.add_edge(ss, i, demand[i])); + total += demand[i]; + } else if (demand[i] < 0) { + aux.push_back(mf.add_edge(i, tt, -demand[i])); + } + } + return total; } - return total; - } - - bool feasible() { - vector aux; - aux.reserve(n); - ll total = add_demands(aux); - int ss = n, tt = n + 1; - ll flow = mf.max_flow(ss, tt); - for (auto ref : aux) mf.clear_edge(ref); - return flow == total; - } - - pair max_flow(int s, int t) { - if (s == t) return {feasible(), 0}; // edge: trivial s == t - vector aux; - aux.reserve(n + 1); - int ss = n, tt = n + 1; - auto ts = mf.add_edge(t, s, INF); - ll total = add_demands(aux); - ll flow = mf.max_flow(ss, tt); - if (flow != total) { - mf.clear_edge(ts); - for (auto ref : aux) mf.clear_edge(ref); - return {false, 0}; + + bool feasible() { + vector aux; + aux.reserve(n); + ll total = add_demands(aux); + int ss = n, tt = n + 1; + ll flow = mf.max_flow(ss, tt); + for (auto ref : aux) mf.clear_edge(ref); + return flow == total; + } + + pair max_flow(int s, int t) { + if (s == t) return {feasible(), 0}; // edge: trivial s == t + vector aux; + aux.reserve(n + 1); + int ss = n, tt = n + 1; + auto ts = mf.add_edge(t, s, INF); + ll total = add_demands(aux); + ll flow = mf.max_flow(ss, tt); + if (flow != total) { + mf.clear_edge(ts); + for (auto ref : aux) mf.clear_edge(ref); + return {false, 0}; + } + ll base = mf.edge_flow(ts); + mf.clear_edge(ts); + for (auto ref : aux) mf.clear_edge(ref); + ll extra = mf.max_flow(s, t); + return {true, base + extra}; } - ll base = mf.edge_flow(ts); - mf.clear_edge(ts); - for (auto ref : aux) mf.clear_edge(ref); - ll extra = mf.max_flow(s, t); - return {true, base + extra}; - } }; // lr_mcmf (0-based). @@ -397,86 +397,86 @@ struct lr_dinic { // constraint: 0 <= lo <= hi, no negative cycle, single-use (call init(n) to reuse) // usage: lr_mcmf f(n); f.add_edge(u, v, lo, hi, cost); auto [ok, r] = f.max_flow(s, t); struct lr_mcmf { - struct edge_info { - mcmf::edge_ref ref; - ll lo; - }; - - int n; - mcmf mf; - vector demand; - vector edges; - - lr_mcmf(int n = 0) { init(n); } - - void init(int n_) { - n = n_; - mf.init(n + 2); - demand.assign(n, 0); - edges.clear(); - } - - int add_edge(int u, int v, ll lo, ll hi, ll cost) { - // goal: store lower bounds via node demands - demand[u] -= lo; - demand[v] += lo; - edges.push_back({mf.add_edge(u, v, hi - lo, cost), lo}); - return (int)edges.size() - 1; - } - - ll edge_flow(int id) const { - // goal: actual flow with lower bound restored - return edges[id].lo + mf.edge_flow(edges[id].ref); - } - - ll add_demands(vector &aux) { - // goal: connect ss/tt for feasible circulation - ll total = 0; - int ss = n, tt = n + 1; - for (int i = 0; i < n; i++) { - if (demand[i] > 0) { - aux.push_back(mf.add_edge(ss, i, demand[i], 0)); - total += demand[i]; - } else if (demand[i] < 0) { - aux.push_back(mf.add_edge(i, tt, -demand[i], 0)); - } + struct edge_info { + mcmf::edge_ref ref; + ll lo; + }; + + int n; + mcmf mf; + vector demand; + vector edges; + + lr_mcmf(int n = 0) { init(n); } + + void init(int n_) { + n = n_; + mf.init(n + 2); + demand.assign(n, 0); + edges.clear(); + } + + int add_edge(int u, int v, ll lo, ll hi, ll cost) { + // goal: store lower bounds via node demands + demand[u] -= lo; + demand[v] += lo; + edges.push_back({mf.add_edge(u, v, hi - lo, cost), lo}); + return (int)edges.size() - 1; + } + + ll edge_flow(int id) const { + // goal: actual flow with lower bound restored + return edges[id].lo + mf.edge_flow(edges[id].ref); } - return total; - } - - pair feasible(bool init_pot = true) { - vector aux; - aux.reserve(n); - ll total = add_demands(aux); - int ss = n, tt = n + 1; - pll res = mf.min_cost_max_flow(ss, tt, total, init_pot); - for (auto ref : aux) mf.clear_edge(ref); - return {res.fr == total, res.sc}; - } - - pair max_flow(int s, int t, bool init_pot = true) { - if (s == t) { - auto r = feasible(init_pot); - return {r.fr, {0, r.sc}}; + + ll add_demands(vector &aux) { + // goal: connect ss/tt for feasible circulation + ll total = 0; + int ss = n, tt = n + 1; + for (int i = 0; i < n; i++) { + if (demand[i] > 0) { + aux.push_back(mf.add_edge(ss, i, demand[i], 0)); + total += demand[i]; + } else if (demand[i] < 0) { + aux.push_back(mf.add_edge(i, tt, -demand[i], 0)); + } + } + return total; + } + + pair feasible(bool init_pot = true) { + vector aux; + aux.reserve(n); + ll total = add_demands(aux); + int ss = n, tt = n + 1; + pll res = mf.min_cost_max_flow(ss, tt, total, init_pot); + for (auto ref : aux) mf.clear_edge(ref); + return {res.fr == total, res.sc}; } - vector aux; - aux.reserve(n + 1); - int ss = n, tt = n + 1; - auto ts = mf.add_edge(t, s, INF, 0); - ll total = add_demands(aux); - pll res = mf.min_cost_max_flow(ss, tt, total, init_pot); - if (res.fr != total) { - mf.clear_edge(ts); - for (auto ref : aux) mf.clear_edge(ref); - return {false, {0, 0}}; + + pair max_flow(int s, int t, bool init_pot = true) { + if (s == t) { + auto r = feasible(init_pot); + return {r.fr, {0, r.sc}}; + } + vector aux; + aux.reserve(n + 1); + int ss = n, tt = n + 1; + auto ts = mf.add_edge(t, s, INF, 0); + ll total = add_demands(aux); + pll res = mf.min_cost_max_flow(ss, tt, total, init_pot); + if (res.fr != total) { + mf.clear_edge(ts); + for (auto ref : aux) mf.clear_edge(ref); + return {false, {0, 0}}; + } + ll base = mf.edge_flow(ts); + ll cost = res.sc; + mf.clear_edge(ts); + for (auto ref : aux) mf.clear_edge(ref); + pll extra = mf.min_cost_max_flow(s, t, INF, init_pot); + return {true, {base + extra.fr, cost + extra.sc}}; } - ll base = mf.edge_flow(ts); - ll cost = res.sc; - mf.clear_edge(ts); - for (auto ref : aux) mf.clear_edge(ref); - pll extra = mf.min_cost_max_flow(s, t, INF, init_pot); - return {true, {base + extra.fr, cost + extra.sc}}; - } }; } // namespace flow diff --git a/src/3-optimizations/hungarian.cpp b/src/3-optimizations/hungarian.cpp index ce8aeb6..f0f4ce3 100644 --- a/src/3-optimizations/hungarian.cpp +++ b/src/3-optimizations/hungarian.cpp @@ -3,37 +3,37 @@ // PRECONDITION: 1 <= n <= m, a is 1-indexed [1..n][1..m] constexpr ll INF = 1e18; ll hungarian(int n, int m, const vector> &a) { - vector u(n + 1), v(m + 1); - vector p(m + 1), way(m + 1); - for (int i = 1; i <= n; i++) { - p[0] = i; - int j0 = 0; - vector minv(m + 1, INF); - vector used(m + 1, 0); - do { - used[j0] = 1; - int i0 = p[j0], j1; - ll delta = INF; - for (int j = 1; j <= m; j++) - if (!used[j]) { - ll cur = a[i0][j] - u[i0] - v[j]; - if (cur < minv[j]) - minv[j] = cur, way[j] = j0; - if (minv[j] < delta) - delta = minv[j], j1 = j; - } - for (int j = 0; j <= m; ++j) - if (used[j]) - u[p[j]] += delta, v[j] -= delta; - else - minv[j] -= delta; - j0 = j1; - } while (p[j0] != 0); - do { - int j1 = way[j0]; - p[j0] = p[j1]; - j0 = j1; - } while (j0); - } - return -v[0]; + vector u(n + 1), v(m + 1); + vector p(m + 1), way(m + 1); + for (int i = 1; i <= n; i++) { + p[0] = i; + int j0 = 0; + vector minv(m + 1, INF); + vector used(m + 1, 0); + do { + used[j0] = 1; + int i0 = p[j0], j1; + ll delta = INF; + for (int j = 1; j <= m; j++) + if (!used[j]) { + ll cur = a[i0][j] - u[i0] - v[j]; + if (cur < minv[j]) + minv[j] = cur, way[j] = j0; + if (minv[j] < delta) + delta = minv[j], j1 = j; + } + for (int j = 0; j <= m; ++j) + if (used[j]) + u[p[j]] += delta, v[j] -= delta; + else + minv[j] -= delta; + j0 = j1; + } while (p[j0] != 0); + do { + int j1 = way[j0]; + p[j0] = p[j1]; + j0 = j1; + } while (j0); + } + return -v[0]; } \ No newline at end of file diff --git a/src/4-string/aho_corasick.cpp b/src/4-string/aho_corasick.cpp index be055e5..2e85f0e 100644 --- a/src/4-string/aho_corasick.cpp +++ b/src/4-string/aho_corasick.cpp @@ -3,83 +3,83 @@ const char st = 'a'; const int MAXC = 'z' - 'a' + 1; struct trie { - trie *child[MAXC]; - trie *fail; - bool term; - trie() { - fill(child, child + MAXC, nullptr); - fail = nullptr; - term = false; - } - ~trie() { - for (int i = 0; i < MAXC; i++) - if (child[i]) delete child[i]; - } - void insert(const string &s, int key = 0) { - if (s.size() == key) term = true; - else { - int next = s[key] - st; - if (!child[next]) child[next] = new trie; - child[next]->insert(s, key + 1); + trie *child[MAXC]; + trie *fail; + bool term; + trie() { + fill(child, child + MAXC, nullptr); + fail = nullptr; + term = false; + } + ~trie() { + for (int i = 0; i < MAXC; i++) + if (child[i]) delete child[i]; + } + void insert(const string &s, int key = 0) { + if (s.size() == key) term = true; + else { + int next = s[key] - st; + if (!child[next]) child[next] = new trie; + child[next]->insert(s, key + 1); + } } - } }; trie *root = new trie; void getFail() { - queue q; - q.push(root); - root->fail = root; - while (!q.empty()) { - trie *now = q.front(); - q.pop(); - for (int i = 0; i < MAXC; i++) { - trie *next = now->child[i]; - if (!next) continue; - if (now == root) next->fail = root; - else { - trie *t = now->fail; - while (t != root && !t->child[i]) - t = t->fail; - if (t->child[i]) t = t->child[i]; - next->fail = t; - } - if (next->fail->term) next->term = true; - q.push(next); + queue q; + q.push(root); + root->fail = root; + while (!q.empty()) { + trie *now = q.front(); + q.pop(); + for (int i = 0; i < MAXC; i++) { + trie *next = now->child[i]; + if (!next) continue; + if (now == root) next->fail = root; + else { + trie *t = now->fail; + while (t != root && !t->child[i]) + t = t->fail; + if (t->child[i]) t = t->child[i]; + next->fail = t; + } + if (next->fail->term) next->term = true; + q.push(next); + } } - } } bool isMatch(const string &s) { - trie *now = root; - bool ret = false; - for (int c = 0; c < s.size(); c++) { - int next = s[c] - st; - while (now != root && !now->child[next]) - now = now->fail; - if (now->child[next]) - now = now->child[next]; - if (now->term) { - ret = true; - break; + trie *now = root; + bool ret = false; + for (int c = 0; c < s.size(); c++) { + int next = s[c] - st; + while (now != root && !now->child[next]) + now = now->fail; + if (now->child[next]) + now = now->child[next]; + if (now->term) { + ret = true; + break; + } } - } - return ret; + return ret; } int main() { - int N; - cin >> N; - for (int i = 0; i < N; i++) { - string s; - cin >> s; - root->insert(s); - } - getFail(); - int M; - cin >> M; - for (int i = 0; i < M; i++) { - string s; - cin >> s; - if (isMatch(s)) cout << "YES\n"; - else cout << "NO\n"; - } - delete root; + int N; + cin >> N; + for (int i = 0; i < N; i++) { + string s; + cin >> s; + root->insert(s); + } + getFail(); + int M; + cin >> M; + for (int i = 0; i < M; i++) { + string s; + cin >> s; + if (isMatch(s)) cout << "YES\n"; + else cout << "NO\n"; + } + delete root; } \ No newline at end of file diff --git a/src/4-string/kmp_algorithm.cpp b/src/4-string/kmp_algorithm.cpp index 547337e..7395968 100644 --- a/src/4-string/kmp_algorithm.cpp +++ b/src/4-string/kmp_algorithm.cpp @@ -1,33 +1,33 @@ #include "../common/common.hpp" vector getpi(const string &P) { - vector pi(sz(P)); - for (int i = 1, j = 0; i < sz(P); i++) { - while (j > 0 && P[i] != P[j]) j = pi[j - 1]; - if (P[i] == P[j]) pi[i] = ++j; - } - return pi; + vector pi(sz(P)); + for (int i = 1, j = 0; i < sz(P); i++) { + while (j > 0 && P[i] != P[j]) j = pi[j - 1]; + if (P[i] == P[j]) pi[i] = ++j; + } + return pi; } vector kmp(const string &T, const string &P) { - vector ret; - vector pi = getpi(P); - for (int i = 0, j = 0; i < sz(T); i++) { - while (j > 0 && T[i] != P[j]) j = pi[j - 1]; - if (T[i] == P[j]) { - if (j == sz(P) - 1) { - ret.push_back(i - (sz(P) - 1)); - j = pi[j]; - } else ++j; + vector ret; + vector pi = getpi(P); + for (int i = 0, j = 0; i < sz(T); i++) { + while (j > 0 && T[i] != P[j]) j = pi[j - 1]; + if (T[i] == P[j]) { + if (j == sz(P) - 1) { + ret.push_back(i - (sz(P) - 1)); + j = pi[j]; + } else ++j; + } } - } - return ret; + return ret; } int main() { - string T, P; - getline(cin, T); - getline(cin, P); - vector ans = kmp(T, P); - cout << sz(ans) << '\n'; - for (int i : ans) - cout << i + 1 << '\n'; + string T, P; + getline(cin, T); + getline(cin, P); + vector ans = kmp(T, P); + cout << sz(ans) << '\n'; + for (int i : ans) + cout << i + 1 << '\n'; } \ No newline at end of file diff --git a/src/4-string/manachers_algorithm.cpp b/src/4-string/manachers_algorithm.cpp index 3d1dc90..30be562 100644 --- a/src/4-string/manachers_algorithm.cpp +++ b/src/4-string/manachers_algorithm.cpp @@ -6,39 +6,39 @@ int n; // n: length of string string s; vector p; // p[i]: the radius of the palindrome at the current position i void manacher() { - // Preprocessing for determining even-length pelindromes - n = sz(s); - s.resize(n << 1 | 1); - p.resize(n << 1 | 1); - for (int i = n - 1; i >= 0; i--) { - s[i << 1 | 1] = s[i]; - s[i << 1] = '#'; - } - n <<= 1; - s[n++] = '#'; - // Processing - int r = -1, c = -1; - // r: end of palindrome - // c: center of palindrome - for (int i = 0; i < n; i++) { - if (i <= r) p[i] = min(r - i, p[c * 2 - i]); - else p[i] = 0; - while (1) { - if (i - p[i] - 1 < 0 || i + p[i] + 1 >= n) break; - if (s[i + p[i] + 1] != s[i - p[i] - 1]) break; - p[i]++; + // Preprocessing for determining even-length pelindromes + n = sz(s); + s.resize(n << 1 | 1); + p.resize(n << 1 | 1); + for (int i = n - 1; i >= 0; i--) { + s[i << 1 | 1] = s[i]; + s[i << 1] = '#'; } - if (i + p[i] > r) { - r = i + p[i], c = i; + n <<= 1; + s[n++] = '#'; + // Processing + int r = -1, c = -1; + // r: end of palindrome + // c: center of palindrome + for (int i = 0; i < n; i++) { + if (i <= r) p[i] = min(r - i, p[c * 2 - i]); + else p[i] = 0; + while (1) { + if (i - p[i] - 1 < 0 || i + p[i] + 1 >= n) break; + if (s[i + p[i] + 1] != s[i - p[i] - 1]) break; + p[i]++; + } + if (i + p[i] > r) { + r = i + p[i], c = i; + } } - } } int main() { - cin >> s; - manacher(); - // Get answer - int ans = 0; - for (int i = 0; i < n; i++) - ans = max(ans, p[i]); - cout << ans; + cin >> s; + manacher(); + // Get answer + int ans = 0; + for (int i = 0; i < n; i++) + ans = max(ans, p[i]); + cout << ans; } \ No newline at end of file diff --git a/src/4-string/rabin_karp_algorithm.cpp b/src/4-string/rabin_karp_algorithm.cpp index 55bd944..acda8b5 100644 --- a/src/4-string/rabin_karp_algorithm.cpp +++ b/src/4-string/rabin_karp_algorithm.cpp @@ -6,32 +6,32 @@ string T, P; ll d = 128, dexp1[MAX], dexp2[MAX]; vector ans; void rabinKarp() { - int len = sz(P); - ll p1 = 0, p2 = 0, t1 = 0, t2 = 0; - for (int i = 0; i < len; i++) { - p1 = (d * p1 + P[i]) % MOD1; - p2 = (d * p2 + P[i]) % MOD2; - t1 = (d * t1 + T[i]) % MOD1; - t2 = (d * t2 + T[i]) % MOD2; - } - if (p1 == t1 && p2 == t2) ans.push_back(0); - for (int i = 1; i < sz(T) - len + 1; i++) { - t1 = (d * (t1 - dexp1[len - 1] * T[i - 1]) + T[i + len - 1]) % MOD1; - t1 = (t1 + MOD1) % MOD1; - t2 = (d * (t2 - dexp2[len - 1] * T[i - 1]) + T[i + len - 1]) % MOD2; - t2 = (t2 + MOD2) % MOD2; - if (p1 == t1 && p2 == t2) ans.push_back(i); - } + int len = sz(P); + ll p1 = 0, p2 = 0, t1 = 0, t2 = 0; + for (int i = 0; i < len; i++) { + p1 = (d * p1 + P[i]) % MOD1; + p2 = (d * p2 + P[i]) % MOD2; + t1 = (d * t1 + T[i]) % MOD1; + t2 = (d * t2 + T[i]) % MOD2; + } + if (p1 == t1 && p2 == t2) ans.push_back(0); + for (int i = 1; i < sz(T) - len + 1; i++) { + t1 = (d * (t1 - dexp1[len - 1] * T[i - 1]) + T[i + len - 1]) % MOD1; + t1 = (t1 + MOD1) % MOD1; + t2 = (d * (t2 - dexp2[len - 1] * T[i - 1]) + T[i + len - 1]) % MOD2; + t2 = (t2 + MOD2) % MOD2; + if (p1 == t1 && p2 == t2) ans.push_back(i); + } } int main() { - dexp1[0] = dexp2[0] = 1; - for (int i = 1; i < MAX; i++) { - dexp1[i] = d * dexp1[i - 1] % MOD1; - dexp2[i] = d * dexp2[i - 1] % MOD2; - } - getline(cin, T); - getline(cin, P); - rabinKarp(); - cout << sz(ans) << '\n'; - for (int i : ans) cout << i + 1 << ' '; + dexp1[0] = dexp2[0] = 1; + for (int i = 1; i < MAX; i++) { + dexp1[i] = d * dexp1[i - 1] % MOD1; + dexp2[i] = d * dexp2[i - 1] % MOD2; + } + getline(cin, T); + getline(cin, P); + rabinKarp(); + cout << sz(ans) << '\n'; + for (int i : ans) cout << i + 1 << ' '; } \ No newline at end of file diff --git a/src/4-string/suffix_array.cpp b/src/4-string/suffix_array.cpp index c454879..8022074 100644 --- a/src/4-string/suffix_array.cpp +++ b/src/4-string/suffix_array.cpp @@ -5,42 +5,42 @@ // Kasai's Algorithm for LCP(Longest Common Prefix) // Time Complexity: O(n) vector buildsa(const string &s) { - int n = sz(s); - vector sa(n), r(n + 1), nr(n + 1); - for (int i = 0; i < n; i++) sa[i] = i, r[i] = s[i]; - for (int d = 1; d < n; d <<= 1) { - auto cmp = [&](int i, int j) { - if (r[i] ^ r[j]) return r[i] < r[j]; - return r[i + d] < r[j + d]; - }; - sort(sa.begin(), sa.end(), cmp); - nr[sa[0]] = 1; - for (int i = 1; i < n; i++) - nr[sa[i]] = nr[sa[i - 1]] + cmp(sa[i - 1], sa[i]); - r = nr; - } - return sa; + int n = sz(s); + vector sa(n), r(n + 1), nr(n + 1); + for (int i = 0; i < n; i++) sa[i] = i, r[i] = s[i]; + for (int d = 1; d < n; d <<= 1) { + auto cmp = [&](int i, int j) { + if (r[i] ^ r[j]) return r[i] < r[j]; + return r[i + d] < r[j + d]; + }; + sort(sa.begin(), sa.end(), cmp); + nr[sa[0]] = 1; + for (int i = 1; i < n; i++) + nr[sa[i]] = nr[sa[i - 1]] + cmp(sa[i - 1], sa[i]); + r = nr; + } + return sa; } vector buildlcp(const string &s, const vector &sa) { - int n = sz(s); - vector lcp(n), isa(n); - for (int i = 0; i < n; i++) isa[sa[i]] = i; - for (int k = 0, i = 0; i < n; i++) - if (isa[i]) { - for (int j = sa[isa[i] - 1]; s[i + k] == s[j + k]; k++); - lcp[isa[i]] = (k ? k-- : 0); - } - return lcp; + int n = sz(s); + vector lcp(n), isa(n); + for (int i = 0; i < n; i++) isa[sa[i]] = i; + for (int k = 0, i = 0; i < n; i++) + if (isa[i]) { + for (int j = sa[isa[i] - 1]; s[i + k] == s[j + k]; k++); + lcp[isa[i]] = (k ? k-- : 0); + } + return lcp; } int main() { - string s; - cin >> s; - vector sa = buildsa(s); - vector lcp = buildlcp(s, sa); - for (auto &i : sa) cout << i + 1 << ' '; - cout << '\n'; - cout << "x "; - for (int i = 1; i < sz(lcp); i++) cout << lcp[i] << ' '; + string s; + cin >> s; + vector sa = buildsa(s); + vector lcp = buildlcp(s, sa); + for (auto &i : sa) cout << i + 1 << ' '; + cout << '\n'; + cout << "x "; + for (int i = 1; i < sz(lcp); i++) cout << lcp[i] << ' '; } // Manber-Myers Algorithm for Suffix Array // Time Conplexity: O(nlogn) @@ -49,47 +49,47 @@ int main() { // BOJ 9248 AC Code // https://www.acmicpc.net/problem/9248 vector buildsa(const string &s) { - int n = sz(s), m = max(256, n) + 1; - vector sa(n), r(2 * n), nr(2 * n), cnt(m), idx(n); - for (int i = 0; i < n; i++) sa[i] = i, r[i] = s[i]; - for (int d = 1; d < n; d <<= 1) { - auto cmp = [&](int i, int j) { - if (r[i] ^ r[j]) return r[i] < r[j]; - return r[i + d] < r[j + d]; - }; - for (int i = 0; i < m; i++) cnt[i] = 0; - for (int i = 0; i < n; i++) cnt[r[i + d]]++; - for (int i = 1; i < m; i++) cnt[i] += cnt[i - 1]; - for (int i = n - 1; ~i; i--) idx[--cnt[r[i + d]]] = i; - for (int i = 0; i < m; i++) cnt[i] = 0; - for (int i = 0; i < n; i++) cnt[r[i]]++; - for (int i = 1; i < m; i++) cnt[i] += cnt[i - 1]; - for (int i = n - 1; ~i; i--) sa[--cnt[r[idx[i]]]] = idx[i]; - nr[sa[0]] = 1; - for (int i = 1; i < n; i++) nr[sa[i]] = nr[sa[i - 1]] + cmp(sa[i - 1], sa[i]); - for (int i = 0; i < n; i++) r[i] = nr[i]; - if (r[sa[n - 1]] == n) break; - } - return sa; + int n = sz(s), m = max(256, n) + 1; + vector sa(n), r(2 * n), nr(2 * n), cnt(m), idx(n); + for (int i = 0; i < n; i++) sa[i] = i, r[i] = s[i]; + for (int d = 1; d < n; d <<= 1) { + auto cmp = [&](int i, int j) { + if (r[i] ^ r[j]) return r[i] < r[j]; + return r[i + d] < r[j + d]; + }; + for (int i = 0; i < m; i++) cnt[i] = 0; + for (int i = 0; i < n; i++) cnt[r[i + d]]++; + for (int i = 1; i < m; i++) cnt[i] += cnt[i - 1]; + for (int i = n - 1; ~i; i--) idx[--cnt[r[i + d]]] = i; + for (int i = 0; i < m; i++) cnt[i] = 0; + for (int i = 0; i < n; i++) cnt[r[i]]++; + for (int i = 1; i < m; i++) cnt[i] += cnt[i - 1]; + for (int i = n - 1; ~i; i--) sa[--cnt[r[idx[i]]]] = idx[i]; + nr[sa[0]] = 1; + for (int i = 1; i < n; i++) nr[sa[i]] = nr[sa[i - 1]] + cmp(sa[i - 1], sa[i]); + for (int i = 0; i < n; i++) r[i] = nr[i]; + if (r[sa[n - 1]] == n) break; + } + return sa; } vector buildlcp(const string &s, const vector &sa) { - int n = sz(s); - vector lcp(n), isa(n); - for (int i = 0; i < n; i++) isa[sa[i]] = i; - for (int k = 0, i = 0; i < n; i++) - if (isa[i]) { - for (int j = sa[isa[i] - 1]; s[i + k] == s[j + k]; k++); - lcp[isa[i]] = (k ? k-- : 0); - } - return lcp; + int n = sz(s); + vector lcp(n), isa(n); + for (int i = 0; i < n; i++) isa[sa[i]] = i; + for (int k = 0, i = 0; i < n; i++) + if (isa[i]) { + for (int j = sa[isa[i] - 1]; s[i + k] == s[j + k]; k++); + lcp[isa[i]] = (k ? k-- : 0); + } + return lcp; } int main() { - string s; - cin >> s; - vector sa = buildsa(s); - vector lcp = buildlcp(s, sa); - for (auto &i : sa) cout << i + 1 << ' '; - cout << '\n'; - cout << "x "; - for (int i = 1; i < sz(lcp); i++) cout << lcp[i] << ' '; + string s; + cin >> s; + vector sa = buildsa(s); + vector lcp = buildlcp(s, sa); + for (auto &i : sa) cout << i + 1 << ' '; + cout << '\n'; + cout << "x "; + for (int i = 1; i < sz(lcp); i++) cout << lcp[i] << ' '; } \ No newline at end of file diff --git a/src/4-string/trie.cpp b/src/4-string/trie.cpp index e74649a..1f392f9 100644 --- a/src/4-string/trie.cpp +++ b/src/4-string/trie.cpp @@ -5,97 +5,97 @@ const char st = '0'; const int MAXC = '9' - '0' + 1; const int MAXN = 100 * 100 * MAXC + 1; struct trie { - int cnt, t[MAXN][MAXC]; - bool term[MAXN]; - void clear() { - memset(t, 0, sizeof(t)); - memset(term, 0, sizeof(term)); - cnt = 0; - } - void insert(string &s) { - int here = 0; - for (char &i : s) { - if (!t[here][i - st]) t[here][i - st] = ++cnt; - here = t[here][i - st]; + int cnt, t[MAXN][MAXC]; + bool term[MAXN]; + void clear() { + memset(t, 0, sizeof(t)); + memset(term, 0, sizeof(term)); + cnt = 0; } - term[here] = true; - } - bool find(string &s) { - int here = 0; - for (int i = 0; i < s.size(); i++) { - if (!t[here][s[i] - st]) return false; - here = t[here][s[i] - st]; - if (i == s.size() - 1 && term[here]) return true; + void insert(string &s) { + int here = 0; + for (char &i : s) { + if (!t[here][i - st]) t[here][i - st] = ++cnt; + here = t[here][i - st]; + } + term[here] = true; + } + bool find(string &s) { + int here = 0; + for (int i = 0; i < s.size(); i++) { + if (!t[here][s[i] - st]) return false; + here = t[here][s[i] - st]; + if (i == s.size() - 1 && term[here]) return true; + } + return false; } - return false; - } }; trie T; int main() { - int N; - cin >> N; - for (int i = 0; i < N; i++) { - string s; - cin >> s; - T.insert(s); - } - int Q; - cin >> Q; - while (Q--) { - string s; - cin >> s; - if (T.find(s)) cout << "Is exist.\n"; - else cout << "Is not exist.\n"; - } + int N; + cin >> N; + for (int i = 0; i < N; i++) { + string s; + cin >> s; + T.insert(s); + } + int Q; + cin >> Q; + while (Q--) { + string s; + cin >> s; + if (T.find(s)) cout << "Is exist.\n"; + else cout << "Is not exist.\n"; + } } // 2. Trie (Pointer) const char st = 'a'; const int MAXC = 'z' - 'a' + 1; struct trie { - trie *child[MAXC]; - bool term; - trie() { - fill(child, child + MAXC, nullptr); - term = false; - } - ~trie() { - for (int i = 0; i < MAXC; i++) - if (child[i]) delete child[i]; - } - void insert(const string &s, int key = 0) { - if (s.size() == key) term = true; - else { - int next = s[key] - st; - if (!child[next]) child[next] = new trie; - child[next]->insert(s, key + 1); + trie *child[MAXC]; + bool term; + trie() { + fill(child, child + MAXC, nullptr); + term = false; + } + ~trie() { + for (int i = 0; i < MAXC; i++) + if (child[i]) delete child[i]; } - } - bool find(const string &s, int key = 0) { - if (s.size() == key) return term; - else { - int next = s[key] - st; - if (!child[next]) return false; - else return child[next]->find(s, key + 1); + void insert(const string &s, int key = 0) { + if (s.size() == key) term = true; + else { + int next = s[key] - st; + if (!child[next]) child[next] = new trie; + child[next]->insert(s, key + 1); + } + } + bool find(const string &s, int key = 0) { + if (s.size() == key) return term; + else { + int next = s[key] - st; + if (!child[next]) return false; + else return child[next]->find(s, key + 1); + } } - } }; int main() { - trie *root = new trie; - int N; - cin >> N; - for (int i = 0; i < N; i++) { - string s; - cin >> s; - root->insert(s); - } - int Q; - cin >> Q; - while (Q--) { - string s; - cin >> s; - if (root->find(s)) cout << "Is exist.\n"; - else cout << "Is not exist.\n"; - } - delete root; + trie *root = new trie; + int N; + cin >> N; + for (int i = 0; i < N; i++) { + string s; + cin >> s; + root->insert(s); + } + int Q; + cin >> Q; + while (Q--) { + string s; + cin >> s; + if (root->find(s)) cout << "Is exist.\n"; + else cout << "Is not exist.\n"; + } + delete root; } diff --git a/src/4-string/z_algorithm.cpp b/src/4-string/z_algorithm.cpp index afb82e0..314ccd9 100644 --- a/src/4-string/z_algorithm.cpp +++ b/src/4-string/z_algorithm.cpp @@ -7,40 +7,40 @@ const int MAXS = 1010101; string s; int z[MAXS]; void input() { - string du; - cin >> du; - for (int i = sz(du) - 1; i >= 0; i--) - s.push_back(du[i]); + string du; + cin >> du; + for (int i = sz(du) - 1; i >= 0; i--) + s.push_back(du[i]); } void zfunction() { - z[0] = sz(s); - int l = 0, r = 0; - for (int i = 1; i < sz(s); i++) { - if (i > r) { - l = r = i; - while (r < sz(s) && s[r - l] == s[r]) r++; - z[i] = r - l; - r--; - } else { - int k = i - l; - if (z[k] < r - i + 1) z[i] = z[k]; - else { - l = i; - while (r < sz(s) && s[r - l] == s[r]) r++; - z[i] = r - l; - r--; - } + z[0] = sz(s); + int l = 0, r = 0; + for (int i = 1; i < sz(s); i++) { + if (i > r) { + l = r = i; + while (r < sz(s) && s[r - l] == s[r]) r++; + z[i] = r - l; + r--; + } else { + int k = i - l; + if (z[k] < r - i + 1) z[i] = z[k]; + else { + l = i; + while (r < sz(s) && s[r - l] == s[r]) r++; + z[i] = r - l; + r--; + } + } } - } } int main() { - input(); - zfunction(); - int q; - cin >> q; - while (q--) { - int x; - cin >> x; - cout << z[sz(s) - x] << '\n'; - } + input(); + zfunction(); + int q; + cin >> q; + while (q--) { + int x; + cin >> x; + cout << z[sz(s) - x] << '\n'; + } } \ No newline at end of file diff --git a/src/5-geometry/bulldozer_trick.cpp b/src/5-geometry/bulldozer_trick.cpp index be17b64..7049f0d 100644 --- a/src/5-geometry/bulldozer_trick.cpp +++ b/src/5-geometry/bulldozer_trick.cpp @@ -4,43 +4,43 @@ // There are a total of O(N^2) results of sorting points on a two-dimensional plane based on an arbitrary axis. // The Bulldozer Trick traverses all O(N^2) results in O(N^2logN) time. struct Point { - ll x, y; - bool operator<(const Point &rhs) const { - return tie(x, y) < tie(rhs.x, rhs.y); - } + ll x, y; + bool operator<(const Point &rhs) const { + return tie(x, y) < tie(rhs.x, rhs.y); + } }; struct Line { - int u, v; - ll dx, dy; // u < v, dx >= 0; - bool operator<(const Line &rhs) const { - if (dy * rhs.dx != rhs.dy * dx) return dy * rhs.dx < rhs.dy * dx; - return tie(u, v) < tie(rhs.u, rhs.v); - } - bool operator==(const Line &rhs) const { - return dy * rhs.dx == rhs.dy * dx; - } + int u, v; + ll dx, dy; // u < v, dx >= 0; + bool operator<(const Line &rhs) const { + if (dy * rhs.dx != rhs.dy * dx) return dy * rhs.dx < rhs.dy * dx; + return tie(u, v) < tie(rhs.u, rhs.v); + } + bool operator==(const Line &rhs) const { + return dy * rhs.dx == rhs.dy * dx; + } }; int n, pos[2020]; Point p[2020]; void bulldozerTrick() { - sort(p + 1, p + 1 + n); - for (int i = 1; i <= n; i++) pos[i] = i; - // find the slope between every two points. - vector arr; - for (int i = 1; i <= n; i++) { - for (int j = i + 1; j <= n; j++) { - arr.push_back({i, j, p[j].x - p[i].x, p[j].y - p[i].y}); - } - } - sort(arr.begin(), arr.end()); - // can check one of the results of sorting points at here. - for (int i = 0, j = 0; i < arr.size(); i = j) { - while (j < arr.size() && arr[j] == arr[i]) j++; // all lines in [i, j) are same - for (int k = i; k < j; k++) { - int u = arr[k].u, v = arr[k].v; - swap(p[pos[u]], p[pos[v]]); - swap(pos[u], pos[v]); + sort(p + 1, p + 1 + n); + for (int i = 1; i <= n; i++) pos[i] = i; + // find the slope between every two points. + vector arr; + for (int i = 1; i <= n; i++) { + for (int j = i + 1; j <= n; j++) { + arr.push_back({i, j, p[j].x - p[i].x, p[j].y - p[i].y}); + } } + sort(arr.begin(), arr.end()); // can check one of the results of sorting points at here. - } + for (int i = 0, j = 0; i < arr.size(); i = j) { + while (j < arr.size() && arr[j] == arr[i]) j++; // all lines in [i, j) are same + for (int k = i; k < j; k++) { + int u = arr[k].u, v = arr[k].v; + swap(p[pos[u]], p[pos[v]]); + swap(pos[u], pos[v]); + } + // can check one of the results of sorting points at here. + } } \ No newline at end of file diff --git a/src/5-geometry/ccw_algorithm.cpp b/src/5-geometry/ccw_algorithm.cpp index 95c20c8..d70b037 100644 --- a/src/5-geometry/ccw_algorithm.cpp +++ b/src/5-geometry/ccw_algorithm.cpp @@ -1,72 +1,72 @@ #include "../common/common.hpp" struct Point { - ll x, y; - bool operator<(const Point &rhs) const { - return (x ^ rhs.x ? x < rhs.x : y < rhs.y); - } - bool operator>(const Point &rhs) const { - return (x ^ rhs.x ? x > rhs.x : y > rhs.y); - } - bool operator==(const Point &rhs) const { - return x == rhs.x && y == rhs.y; - } - Point operator-(const Point &rhs) const { - return {x - rhs.x, y - rhs.y}; - } - ll operator*(const Point &rhs) const { // cross product - return x * rhs.y - y * rhs.x; - } + ll x, y; + bool operator<(const Point &rhs) const { + return (x ^ rhs.x ? x < rhs.x : y < rhs.y); + } + bool operator>(const Point &rhs) const { + return (x ^ rhs.x ? x > rhs.x : y > rhs.y); + } + bool operator==(const Point &rhs) const { + return x == rhs.x && y == rhs.y; + } + Point operator-(const Point &rhs) const { + return {x - rhs.x, y - rhs.y}; + } + ll operator*(const Point &rhs) const { // cross product + return x * rhs.y - y * rhs.x; + } }; ll ccw(const Point &a, const Point &b, const Point &c) { - // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear - ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); - return (res > 0 ? 1 : (res < 0 ? -1 : 0)); + // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear + ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); + return (res > 0 ? 1 : (res < 0 ? -1 : 0)); } // Does the line segment ab and cd intersect? bool isCross(const Point &a, const Point &b, const Point &c, const Point &d) { - ll ab = ccw(a, b, c) * ccw(a, b, d); - ll cd = ccw(c, d, a) * ccw(c, d, b); - if (ab == 0 && cd == 0) { - pii A = {a.x, a.y}, B = {b.x, b.y}, C = {c.x, c.y}, D = {d.x, d.y}; - if (A > B) swap(A, B); - if (C > D) swap(C, D); - return (A <= D && C <= B); - } else return (ab <= 0 && cd <= 0); + ll ab = ccw(a, b, c) * ccw(a, b, d); + ll cd = ccw(c, d, a) * ccw(c, d, b); + if (ab == 0 && cd == 0) { + pii A = {a.x, a.y}, B = {b.x, b.y}, C = {c.x, c.y}, D = {d.x, d.y}; + if (A > B) swap(A, B); + if (C > D) swap(C, D); + return (A <= D && C <= B); + } else return (ab <= 0 && cd <= 0); } ll gcd(ll x, ll y) { - if (!y) return x; - return gcd(y, x % y); + if (!y) return x; + return gcd(y, x % y); } pll getSlope(const Point &a, const Point &b) { - pll slope = {b.y - a.y, b.x - a.x}; - if (slope.sc < 0 || (slope.sc == 0 && slope.fr < 0)) { - slope.fr *= -1, slope.sc *= -1; - } - ll g = gcd(abs(slope.fr), abs(slope.sc)); - slope.fr /= g, slope.sc /= g; - return slope; + pll slope = {b.y - a.y, b.x - a.x}; + if (slope.sc < 0 || (slope.sc == 0 && slope.fr < 0)) { + slope.fr *= -1, slope.sc *= -1; + } + ll g = gcd(abs(slope.fr), abs(slope.sc)); + slope.fr /= g, slope.sc /= g; + return slope; } // Get intersection point of two line segments ab and cd. // Note: ab, cd is not a infinite line, it's a line segment. void getIntersectionPoint(Point a, Point b, Point c, Point d) { - if (isCross(a, b, c, d)) { - cout << 1 << '\n'; - if (getSlope(a, b) == getSlope(c, d)) { - if (a > b) swap(a, b); // wlog a <= b - if (c > d) swap(c, d); // wlog c <= d - if (b == c || a == d) { - if (b == c) cout << b.x << ' ' << b.y; - if (a == d) cout << a.x << ' ' << a.y; - } - } else { - b = b - a; - d = d - c; - double p = (double)((c - a) * d) / (b * d); + if (isCross(a, b, c, d)) { + cout << 1 << '\n'; + if (getSlope(a, b) == getSlope(c, d)) { + if (a > b) swap(a, b); // wlog a <= b + if (c > d) swap(c, d); // wlog c <= d + if (b == c || a == d) { + if (b == c) cout << b.x << ' ' << b.y; + if (a == d) cout << a.x << ' ' << a.y; + } + } else { + b = b - a; + d = d - c; + double p = (double)((c - a) * d) / (b * d); - // res = a + p * b - pair res = {a.x + p * b.x, a.y + p * b.y}; - cout << res.fr << ' ' << res.sc; - } - } else cout << 0 << '\n'; + // res = a + p * b + pair res = {a.x + p * b.x, a.y + p * b.y}; + cout << res.fr << ' ' << res.sc; + } + } else cout << 0 << '\n'; } \ No newline at end of file diff --git a/src/5-geometry/convex_hull.cpp b/src/5-geometry/convex_hull.cpp index 0350f5a..9e92908 100644 --- a/src/5-geometry/convex_hull.cpp +++ b/src/5-geometry/convex_hull.cpp @@ -2,117 +2,117 @@ // 1. Graham Scan struct point { - ll x, y; - bool operator<(const point &rhs) const { - if (y != rhs.y) return y < rhs.y; - return x < rhs.x; - } + ll x, y; + bool operator<(const point &rhs) const { + if (y != rhs.y) return y < rhs.y; + return x < rhs.x; + } }; int N; vector p; vector st; ll ccw(const point &a, const point &b, const point &c) { - // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear - ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); - return (res > 0 ? 1 : (res < 0 ? -1 : 0)); + // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear + ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); + return (res > 0 ? 1 : (res < 0 ? -1 : 0)); } void input() { - cin >> N; - for (int i = 0; i < N; i++) { - int x, y; - cin >> x >> y; - p.push_back({x, y}); - } + cin >> N; + for (int i = 0; i < N; i++) { + int x, y; + cin >> x >> y; + p.push_back({x, y}); + } } ll dist(const point &p1, const point &p2) { - return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); + return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); } bool cmp(const point &p1, const point &p2) { - return (ccw(p[0], p1, p2) > 0 || (ccw(p[0], p1, p2) == 0 && dist(p[0], p1) < dist(p[0], p2))); + return (ccw(p[0], p1, p2) > 0 || (ccw(p[0], p1, p2) == 0 && dist(p[0], p1) < dist(p[0], p2))); } void grahamScan() { - sort(p.begin(), p.end()); - sort(p.begin() + 1, p.end(), cmp); - st.push_back(0); - st.push_back(1); - for (int next = 2; next < N; next++) { - while (st.size() >= 2) { - int first = st.back(); - st.pop_back(); - int second = st.back(); - if (ccw(p[second], p[first], p[next]) > 0) { - st.push_back(first); - break; - } + sort(p.begin(), p.end()); + sort(p.begin() + 1, p.end(), cmp); + st.push_back(0); + st.push_back(1); + for (int next = 2; next < N; next++) { + while (st.size() >= 2) { + int first = st.back(); + st.pop_back(); + int second = st.back(); + if (ccw(p[second], p[first], p[next]) > 0) { + st.push_back(first); + break; + } + } + st.push_back(next); } - st.push_back(next); - } } int main() { - input(); - grahamScan(); - cout << st.size(); + input(); + grahamScan(); + cout << st.size(); } // 2. Monotone Chain struct point { - ll x, y; - bool operator<(const point &rhs) const { - if (x != rhs.x) return x < rhs.x; - else return y < rhs.y; - } + ll x, y; + bool operator<(const point &rhs) const { + if (x != rhs.x) return x < rhs.x; + else return y < rhs.y; + } }; int N; vector p; vector dh, uh; ll ccw(const point &a, const point &b, const point &c) { - // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear - ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); - return (res > 0 ? 1 : (res < 0 ? -1 : 0)); + // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear + ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); + return (res > 0 ? 1 : (res < 0 ? -1 : 0)); } void input() { - cin >> N; - for (int i = 0; i < N; i++) { - int x, y; - cin >> x >> y; - p.push_back({x, y}); - } + cin >> N; + for (int i = 0; i < N; i++) { + int x, y; + cin >> x >> y; + p.push_back({x, y}); + } } void monotoneChain() { - sort(p.begin(), p.end()); - // calculate lower hull - dh.push_back(0); - dh.push_back(1); - for (int next = 2; next < N; next++) { - while (dh.size() >= 2) { - int first = dh.back(); - dh.pop_back(); - int second = dh.back(); - if (ccw(p[second], p[first], p[next]) > 0) { - dh.push_back(first); - break; - } + sort(p.begin(), p.end()); + // calculate lower hull + dh.push_back(0); + dh.push_back(1); + for (int next = 2; next < N; next++) { + while (dh.size() >= 2) { + int first = dh.back(); + dh.pop_back(); + int second = dh.back(); + if (ccw(p[second], p[first], p[next]) > 0) { + dh.push_back(first); + break; + } + } + dh.push_back(next); } - dh.push_back(next); - } - // calculate upper hull - uh.push_back(N - 1); - uh.push_back(N - 2); - for (int next = N - 3; next >= 0; next--) { - while (uh.size() >= 2) { - int first = uh.back(); - uh.pop_back(); - int second = uh.back(); - if (ccw(p[second], p[first], p[next]) > 0) { - uh.push_back(first); - break; - } + // calculate upper hull + uh.push_back(N - 1); + uh.push_back(N - 2); + for (int next = N - 3; next >= 0; next--) { + while (uh.size() >= 2) { + int first = uh.back(); + uh.pop_back(); + int second = uh.back(); + if (ccw(p[second], p[first], p[next]) > 0) { + uh.push_back(first); + break; + } + } + uh.push_back(next); } - uh.push_back(next); - } } int main() { - input(); - monotoneChain(); - cout << (int)dh.size() + (int)uh.size() - 2; + input(); + monotoneChain(); + cout << (int)dh.size() + (int)uh.size() - 2; } \ No newline at end of file diff --git a/src/5-geometry/half_plane_intersection.cpp b/src/5-geometry/half_plane_intersection.cpp index 253df59..cc67ec1 100644 --- a/src/5-geometry/half_plane_intersection.cpp +++ b/src/5-geometry/half_plane_intersection.cpp @@ -7,54 +7,54 @@ // - Returns an empty vector if the intersection is empty or degenerate. // TIME COMPLEXITY: O(nlogn) struct Point { - ld x, y; + ld x, y; }; struct Line { - Point s, t; + Point s, t; }; constexpr ld EPS = 1e-9; inline bool equals(ld a, ld b) { return abs(a - b) < EPS; } bool line_intersect(Point &s1, Point &e1, Point &s2, Point &e2, Point &v) { - ld vx1 = e1.x - s1.x, vy1 = e1.y - s1.y; - ld vx2 = e2.x - s2.x, vy2 = e2.y - s2.y; - ld det = vx1 * (-vy2) - (-vx2) * vy1; - if (equals(det, 0)) return 0; - ld s = (ld)((s2.x - s1.x) * (-vy2) + (s2.y - s1.y) * vx2) / det; - v.x = s1.x + vx1 * s; - v.y = s1.y + vy1 * s; - return 1; + ld vx1 = e1.x - s1.x, vy1 = e1.y - s1.y; + ld vx2 = e2.x - s2.x, vy2 = e2.y - s2.y; + ld det = vx1 * (-vy2) - (-vx2) * vy1; + if (equals(det, 0)) return 0; + ld s = (ld)((s2.x - s1.x) * (-vy2) + (s2.y - s1.y) * vx2) / det; + v.x = s1.x + vx1 * s; + v.y = s1.y + vy1 * s; + return 1; } bool bad(Line &a, Line &b, Line &c) { - Point v; - if (!line_intersect(a.s, a.t, b.s, b.t, v)) return 0; - ld crs = (c.t.x - c.s.x) * (v.y - c.s.y) - (c.t.y - c.s.y) * (v.x - c.s.x); - return crs < 0 || equals(crs, 0); + Point v; + if (!line_intersect(a.s, a.t, b.s, b.t, v)) return 0; + ld crs = (c.t.x - c.s.x) * (v.y - c.s.y) - (c.t.y - c.s.y) * (v.x - c.s.x); + return crs < 0 || equals(crs, 0); } vector hpi(vector &ln) { - auto lsgn = [&](const Line &a) { - if (a.s.y == a.t.y) return a.s.x > a.t.x; - return a.s.y > a.t.y; - }; - sort(ln.begin(), ln.end(), [&](const Line &a, const Line &b) { - if (lsgn(a) != lsgn(b)) return lsgn(a) < lsgn(b); - return (a.t.x - a.s.x) * (b.t.y - b.s.y) - (a.t.y - a.s.y) * (b.t.x - b.s.x) > 0; - }); - deque dq; - for (int i = 0; i < sz(ln); i++) { - while (dq.size() >= 2 && bad(dq[dq.size() - 2], dq.back(), ln[i])) - dq.pop_back(); - while (dq.size() >= 2 && bad(dq[0], dq[1], ln[i])) - dq.pop_front(); - if (dq.size() < 2 || !bad(dq.back(), ln[i], dq[0])) - dq.push_back(ln[i]); - } - vector ret; - if (dq.size() >= 3) - for (int i = 0; i < sz(dq); i++) { - int j = (i + 1) % sz(dq); - Point v; - if (!line_intersect(dq[i].s, dq[i].t, dq[j].s, dq[j].t, v)) continue; - ret.push_back(v); + auto lsgn = [&](const Line &a) { + if (a.s.y == a.t.y) return a.s.x > a.t.x; + return a.s.y > a.t.y; + }; + sort(ln.begin(), ln.end(), [&](const Line &a, const Line &b) { + if (lsgn(a) != lsgn(b)) return lsgn(a) < lsgn(b); + return (a.t.x - a.s.x) * (b.t.y - b.s.y) - (a.t.y - a.s.y) * (b.t.x - b.s.x) > 0; + }); + deque dq; + for (int i = 0; i < sz(ln); i++) { + while (dq.size() >= 2 && bad(dq[dq.size() - 2], dq.back(), ln[i])) + dq.pop_back(); + while (dq.size() >= 2 && bad(dq[0], dq[1], ln[i])) + dq.pop_front(); + if (dq.size() < 2 || !bad(dq.back(), ln[i], dq[0])) + dq.push_back(ln[i]); } - return ret; + vector ret; + if (dq.size() >= 3) + for (int i = 0; i < sz(dq); i++) { + int j = (i + 1) % sz(dq); + Point v; + if (!line_intersect(dq[i].s, dq[i].t, dq[j].s, dq[j].t, v)) continue; + ret.push_back(v); + } + return ret; } diff --git a/src/5-geometry/minimum_enclosing_circle.cpp b/src/5-geometry/minimum_enclosing_circle.cpp index 474cb85..46b61d0 100644 --- a/src/5-geometry/minimum_enclosing_circle.cpp +++ b/src/5-geometry/minimum_enclosing_circle.cpp @@ -5,56 +5,56 @@ // A minimum enclosing circle is a circle in which all the points lie either inside the circle or on its boundaries. // TIME COMPLEXITY: O(N) (using random) struct Point { - long double x, y; + long double x, y; }; struct Circle { - Point c; - long double r; + Point c; + long double r; }; long double dist(const Point &a, const Point &b) { - return sqrt(pow(b.x - a.x, 2) + pow(b.y - a.y, 2)); + return sqrt(pow(b.x - a.x, 2) + pow(b.y - a.y, 2)); } Point getCircleCenter(const Point &a, const Point &b) { - long double A = a.x * a.x + a.y * a.y; - long double B = b.x * b.x + b.y * b.y; - long double C = a.x * b.y - a.y * b.x; - return {(b.y * A - a.y * B) / (2 * C), (a.x * B - b.x * A) / (2 * C)}; + long double A = a.x * a.x + a.y * a.y; + long double B = b.x * b.x + b.y * b.y; + long double C = a.x * b.y - a.y * b.x; + return {(b.y * A - a.y * B) / (2 * C), (a.x * B - b.x * A) / (2 * C)}; } Circle circleFrom(const Point &a, const Point &b, const Point &c) { - Point i = getCircleCenter({b.x - a.x, b.y - a.y}, {c.x - a.x, c.y - a.y}); - i.x += a.x; - i.y += a.y; - return {i, dist(a, i)}; + Point i = getCircleCenter({b.x - a.x, b.y - a.y}, {c.x - a.x, c.y - a.y}); + i.x += a.x; + i.y += a.y; + return {i, dist(a, i)}; } Circle circleFrom(const Point &a, const Point &b) { - Point c = {(a.x + b.x) / 2.0, (a.y + b.y) / 2.0}; - return {c, dist(a, b) / 2.0}; + Point c = {(a.x + b.x) / 2.0, (a.y + b.y) / 2.0}; + return {c, dist(a, b) / 2.0}; } Circle minimumEnclosingCircle(int n, const vector &p) { - Circle ret = {{0, 0}, 0}; - for (int i = 0; i < n; i++) { - if (dist(ret.c, p[i]) <= ret.r) continue; - ret.c = p[i], ret.r = 0; - for (int j = 0; j < i; j++) { - if (dist(ret.c, p[j]) <= ret.r) continue; - ret = circleFrom(p[i], p[j]); - for (int k = 0; k < j; k++) { - if (dist(ret.c, p[k]) <= ret.r) continue; - ret = circleFrom(p[i], p[j], p[k]); - } + Circle ret = {{0, 0}, 0}; + for (int i = 0; i < n; i++) { + if (dist(ret.c, p[i]) <= ret.r) continue; + ret.c = p[i], ret.r = 0; + for (int j = 0; j < i; j++) { + if (dist(ret.c, p[j]) <= ret.r) continue; + ret = circleFrom(p[i], p[j]); + for (int k = 0; k < j; k++) { + if (dist(ret.c, p[k]) <= ret.r) continue; + ret = circleFrom(p[i], p[j], p[k]); + } + } } - } - return ret; + return ret; } int main() { - int n; - cin >> n; - vector p(n); - for (auto &i : p) cin >> i.x >> i.y; - random_shuffle(p.begin(), p.end()); - Circle ans = minimumEnclosingCircle(n, p); - cout << fixed; - cout.precision(3); - cout << ans.c.x << ' ' << ans.c.y << '\n' - << ans.r; + int n; + cin >> n; + vector p(n); + for (auto &i : p) cin >> i.x >> i.y; + random_shuffle(p.begin(), p.end()); + Circle ans = minimumEnclosingCircle(n, p); + cout << fixed; + cout.precision(3); + cout << ans.c.x << ' ' << ans.c.y << '\n' + << ans.r; } \ No newline at end of file diff --git a/src/5-geometry/ray_casting.cpp b/src/5-geometry/ray_casting.cpp index f26cb13..4d59c30 100644 --- a/src/5-geometry/ray_casting.cpp +++ b/src/5-geometry/ray_casting.cpp @@ -1,62 +1,62 @@ #include "../common/common.hpp" struct point { - ll x, y; - bool operator==(const point &rhs) const { - return x == rhs.x && y == rhs.y; - } - bool operator<=(const point &rhs) const { - if (x < rhs.x || (x == rhs.x && y <= rhs.y)) return 1; - else return 0; - } + ll x, y; + bool operator==(const point &rhs) const { + return x == rhs.x && y == rhs.y; + } + bool operator<=(const point &rhs) const { + if (x < rhs.x || (x == rhs.x && y <= rhs.y)) return 1; + else return 0; + } }; int n; vector p; point a, b, c; void input() { - cin >> n; - p.resize(n); - for (auto &i : p) { - cin >> i.x >> i.y; - } - p.push_back(p[0]); - cin >> a.x >> a.y; - cin >> b.x >> b.y; - cin >> c.x >> c.y; + cin >> n; + p.resize(n); + for (auto &i : p) { + cin >> i.x >> i.y; + } + p.push_back(p[0]); + cin >> a.x >> a.y; + cin >> b.x >> b.y; + cin >> c.x >> c.y; } ll ccw(const point &a, const point &b, const point &c) { - // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear - ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); - return (res > 0 ? 1 : (res < 0 ? -1 : 0)); + // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear + ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); + return (res > 0 ? 1 : (res < 0 ? -1 : 0)); } // Does the line segment ab and cd intersect? bool isCross(point a, point b, point c, point d) { - ll ab = ccw(a, b, c) * ccw(a, b, d); - ll cd = ccw(c, d, a) * ccw(c, d, b); - if (ab == 0 && cd == 0) { - pii A = {a.x, a.y}, B = {b.x, b.y}, C = {c.x, c.y}, D = {d.x, d.y}; - if (A > B) swap(A, B); - if (C > D) swap(C, D); - return (A <= D && C <= B); - } else return (ab <= 0 && cd <= 0); + ll ab = ccw(a, b, c) * ccw(a, b, d); + ll cd = ccw(c, d, a) * ccw(c, d, b); + if (ab == 0 && cd == 0) { + pii A = {a.x, a.y}, B = {b.x, b.y}, C = {c.x, c.y}, D = {d.x, d.y}; + if (A > B) swap(A, B); + if (C > D) swap(C, D); + return (A <= D && C <= B); + } else return (ab <= 0 && cd <= 0); } bool insidePolygon(point v) { - point u = {1010101010ll, v.y + 1}; - for (int i = 0; i < n; i++) { - if (p[i] == v) return 1; - } - for (int i = 0; i < n; i++) { - if (!ccw(p[i], p[i + 1], v) && (p[i] <= v ^ p[i + 1] <= v)) return 1; - } - int cnt = 0; - for (int i = 0; i < n; i++) { - cnt += isCross(p[i], p[i + 1], u, v); - } - return cnt & 1; + point u = {1010101010ll, v.y + 1}; + for (int i = 0; i < n; i++) { + if (p[i] == v) return 1; + } + for (int i = 0; i < n; i++) { + if (!ccw(p[i], p[i + 1], v) && (p[i] <= v ^ p[i + 1] <= v)) return 1; + } + int cnt = 0; + for (int i = 0; i < n; i++) { + cnt += isCross(p[i], p[i + 1], u, v); + } + return cnt & 1; } int main() { - input(); - cout << (insidePolygon(a) ? 1 : 0) << '\n'; - cout << (insidePolygon(b) ? 1 : 0) << '\n'; - cout << (insidePolygon(c) ? 1 : 0) << '\n'; + input(); + cout << (insidePolygon(a) ? 1 : 0) << '\n'; + cout << (insidePolygon(b) ? 1 : 0) << '\n'; + cout << (insidePolygon(c) ? 1 : 0) << '\n'; } \ No newline at end of file diff --git a/src/5-geometry/rotating_callipers.cpp b/src/5-geometry/rotating_callipers.cpp index 6f68710..3f45491 100644 --- a/src/5-geometry/rotating_callipers.cpp +++ b/src/5-geometry/rotating_callipers.cpp @@ -1,76 +1,76 @@ #include "../common/common.hpp" struct point { - ll x, y; - bool operator<(const point &rhs) const { - if (x != rhs.x) return x < rhs.x; - return y < rhs.y; - } + ll x, y; + bool operator<(const point &rhs) const { + if (x != rhs.x) return x < rhs.x; + return y < rhs.y; + } }; int n; vector p, ch; point ans1, ans2; void init() { - n = 0; - p.clear(); - ch.clear(); - ans1 = ans2 = {0, 0}; + n = 0; + p.clear(); + ch.clear(); + ans1 = ans2 = {0, 0}; } void input() { - cin >> n; - p.resize(n); - ch.resize(n); - for (auto &i : p) cin >> i.x >> i.y; + cin >> n; + p.resize(n); + ch.resize(n); + for (auto &i : p) cin >> i.x >> i.y; } ll ccw(const point &a, const point &b, const point &c) { - // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear - ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); - return (res > 0 ? 1 : (res < 0 ? -1 : 0)); + // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear + ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); + return (res > 0 ? 1 : (res < 0 ? -1 : 0)); } ll cccw(point a, point b, point c, point d) { - d.x -= c.x - b.x; - d.y -= c.y - b.y; - return ccw(a, b, d); + d.x -= c.x - b.x; + d.y -= c.y - b.y; + return ccw(a, b, d); } ll dist(const point &p1, const point &p2) { - return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); + return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); } bool cmp(const point &p1, const point &p2) { - return (ccw(p[0], p1, p2) > 0 || (ccw(p[0], p1, p2) == 0 && dist(p[0], p1) < dist(p[0], p2))); + return (ccw(p[0], p1, p2) > 0 || (ccw(p[0], p1, p2) == 0 && dist(p[0], p1) < dist(p[0], p2))); } void rotatingCallipers() { - sort(p.begin(), p.end()); - sort(p.begin() + 1, p.end(), cmp); - ch[0] = p[0]; - ch[1] = p[1]; - ll fl = 2, cnt = 2; - for (int i = 2; i < n; i++) { - while (fl >= 2 && ccw(ch[fl - 2], ch[fl - 1], p[i]) <= 0) fl--; - ch[fl] = p[i], fl++; - } - ll fl2 = 1, mx = 0; - for (int i = 0; i < fl; i++) { - while ((fl2 + 1) != i && cccw(ch[i], ch[i + 1], ch[fl2 % fl], ch[(fl2 + 1) % fl]) > 0) { - if (mx < dist(ch[i], ch[fl2 % fl])) { - ans1 = ch[i], ans2 = ch[fl2 % fl]; - mx = dist(ch[i], ch[fl2 % fl]); - } - fl2++; + sort(p.begin(), p.end()); + sort(p.begin() + 1, p.end(), cmp); + ch[0] = p[0]; + ch[1] = p[1]; + ll fl = 2, cnt = 2; + for (int i = 2; i < n; i++) { + while (fl >= 2 && ccw(ch[fl - 2], ch[fl - 1], p[i]) <= 0) fl--; + ch[fl] = p[i], fl++; } - if (mx < dist(ch[i], ch[fl2 % fl])) { - ans1 = ch[i], ans2 = ch[fl2 % fl]; - mx = dist(ch[i], ch[fl2 % fl]); + ll fl2 = 1, mx = 0; + for (int i = 0; i < fl; i++) { + while ((fl2 + 1) != i && cccw(ch[i], ch[i + 1], ch[fl2 % fl], ch[(fl2 + 1) % fl]) > 0) { + if (mx < dist(ch[i], ch[fl2 % fl])) { + ans1 = ch[i], ans2 = ch[fl2 % fl]; + mx = dist(ch[i], ch[fl2 % fl]); + } + fl2++; + } + if (mx < dist(ch[i], ch[fl2 % fl])) { + ans1 = ch[i], ans2 = ch[fl2 % fl]; + mx = dist(ch[i], ch[fl2 % fl]); + } } - } } int main() { - int tc; - cin >> tc; - while (tc--) { - init(); - input(); - rotatingCallipers(); - cout << ans1.x << ' ' << ans1.y << ' '; - cout << ans2.x << ' ' << ans2.y << '\n'; - } + int tc; + cin >> tc; + while (tc--) { + init(); + input(); + rotatingCallipers(); + cout << ans1.x << ' ' << ans1.y << ' '; + cout << ans2.x << ' ' << ans2.y << '\n'; + } } \ No newline at end of file diff --git a/src/5-geometry/sort_by_angular.cpp b/src/5-geometry/sort_by_angular.cpp index 3c49f30..609475f 100644 --- a/src/5-geometry/sort_by_angular.cpp +++ b/src/5-geometry/sort_by_angular.cpp @@ -2,17 +2,17 @@ // Sort by Angular (Relative to Origin) struct Point { - ll x, y; - bool operator<(const Point &rhs) const { - return x ^ rhs.x ? x < rhs.x : y < rhs.y; - } + ll x, y; + bool operator<(const Point &rhs) const { + return x ^ rhs.x ? x < rhs.x : y < rhs.y; + } }; const Point o = {0, 0}; vector p; ll ccw(const Point &a, const Point &b, const Point &c) { - // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear - ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); - return (res > 0 ? 1 : (res < 0 ? -1 : 0)); + // res > 0 -> ccw, res < 0 -> cw, res = 0 -> colinear + ll res = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); + return (res > 0 ? 1 : (res < 0 ? -1 : 0)); } inline ll dist(const Point &v) { return v.x * v.x + v.y * v.y; } // If the angle between any two points and the origin is less than 180 degrees, @@ -20,9 +20,9 @@ inline ll dist(const Point &v) { return v.x * v.x + v.y * v.y; } // Therefore, the points were divided into 1st and 4th quadrants and 2nd and 3rd quadrants, // and the points in the 1st and 4th quadrants were arranged in front. void sortByAngular() { - sort(p.begin(), p.end(), [&](const Point &lhs, const Point &rhs) { - if ((lhs < o) ^ (rhs < o)) return (lhs < o) < (rhs < o); - if (ccw(o, lhs, rhs)) return ccw(o, lhs, rhs) > 0; - return dist(lhs) < dist(rhs); - }); + sort(p.begin(), p.end(), [&](const Point &lhs, const Point &rhs) { + if ((lhs < o) ^ (rhs < o)) return (lhs < o) < (rhs < o); + if (ccw(o, lhs, rhs)) return ccw(o, lhs, rhs) > 0; + return dist(lhs) < dist(rhs); + }); } \ No newline at end of file diff --git a/src/6-math/basic_sqrt_time_algorithms.cpp b/src/6-math/basic_sqrt_time_algorithms.cpp index 4a5149c..4fd3472 100644 --- a/src/6-math/basic_sqrt_time_algorithms.cpp +++ b/src/6-math/basic_sqrt_time_algorithms.cpp @@ -6,13 +6,13 @@ // TIME COMPLEXITY: O(sqrt(x)). vector di; void findingDivisors(int x) { - for (int i = 1; i <= sqrt(x); i++) { - if (x % i == 0) { - di.push_back(i); - if (x / i != i) di.push_back(x / i); + for (int i = 1; i <= sqrt(x); i++) { + if (x % i == 0) { + di.push_back(i); + if (x / i != i) di.push_back(x / i); + } } - } - sort(di.begin(), di.end()); + sort(di.begin(), di.end()); } // 2. Finding Prime Factorization in O(sqrt(x)) @@ -21,15 +21,15 @@ void findingDivisors(int x) { // TIME COMPLEXITY: O(sqrt(x)). vector p; void primeFactorization(int x) { - while (x % 2 == 0) { - x /= 2; - p.push_back(2); - } - for (int i = 3; i <= sqrt(x); i += 2) { - while (x % i == 0) { - x /= i; - p.push_back(i); + while (x % 2 == 0) { + x /= 2; + p.push_back(2); } - } - if (x > 1) p.push_back(x); + for (int i = 3; i <= sqrt(x); i += 2) { + while (x % i == 0) { + x /= i; + p.push_back(i); + } + } + if (x > 1) p.push_back(x); } \ No newline at end of file diff --git a/src/6-math/binomial_coefficient.cpp b/src/6-math/binomial_coefficient.cpp index ba7eee0..a4cb816 100644 --- a/src/6-math/binomial_coefficient.cpp +++ b/src/6-math/binomial_coefficient.cpp @@ -3,56 +3,56 @@ // nCr in O(r) // Beware of integer overflow ll binom(int n, int r) { - if (r < 0 || n < r) return 0; - r = min(r, n - r); - ll ret = 1; - for (ll i = 1; i <= r; i++) { - ret *= n + 1 - i; - ret /= i; - } - return ret; + if (r < 0 || n < r) return 0; + r = min(r, n - r); + ll ret = 1; + for (ll i = 1; i <= r; i++) { + ret *= n + 1 - i; + ret /= i; + } + return ret; } // nCr (Pascal’s Rule) ll binomDP[1010][1010]; void init() { - for (int i = 0; i < 1010; i++) { - for (int j = 0; j < 1010; j++) { - binomDP[i][j] = -1; + for (int i = 0; i < 1010; i++) { + for (int j = 0; j < 1010; j++) { + binomDP[i][j] = -1; + } } - } } ll binom(int n, int r) { - if (r < 0 || n < r) return 0; - ll &ret = binomDP[n][r]; - if (ret != -1) return ret; - if (n == 1) return ret = 1; - return binom(n - 1, r - 1) + binom(n - 1, r); + if (r < 0 || n < r) return 0; + ll &ret = binomDP[n][r]; + if (ret != -1) return ret; + if (n == 1) return ret = 1; + return binom(n - 1, r - 1) + binom(n - 1, r); } // nCr mod p in O(1) const int MOD = 1e9 + 7; const int MAXN = 4040404; ll fac[MAXN], inv[MAXN], facInv[MAXN]; ll binom(int n, int r) { - return fac[n] * facInv[r] % MOD * facInv[n - r] % MOD; + return fac[n] * facInv[r] % MOD * facInv[n - r] % MOD; } int main() { - cin.tie(NULL), cout.tie(NULL); - ios_base::sync_with_stdio(false); - // Preprocessing in O(N) - fac[0] = fac[1] = inv[1] = 1; - facInv[0] = facInv[1] = 1; - for (int i = 2; i < MAXN; i++) { - fac[i] = i * fac[i - 1] % MOD; - inv[i] = -(MOD / i) * inv[MOD % i] % MOD; - if (inv[i] < 0) inv[i] += MOD; - facInv[i] = facInv[i - 1] * inv[i] % MOD; - } - // Answer each query in O(1) - int q; - cin >> q; - while (q--) { - int n, r; - cin >> n >> r; - cout << binom(n, r) << '\n'; - } + cin.tie(NULL), cout.tie(NULL); + ios_base::sync_with_stdio(false); + // Preprocessing in O(N) + fac[0] = fac[1] = inv[1] = 1; + facInv[0] = facInv[1] = 1; + for (int i = 2; i < MAXN; i++) { + fac[i] = i * fac[i - 1] % MOD; + inv[i] = -(MOD / i) * inv[MOD % i] % MOD; + if (inv[i] < 0) inv[i] += MOD; + facInv[i] = facInv[i - 1] * inv[i] % MOD; + } + // Answer each query in O(1) + int q; + cin >> q; + while (q--) { + int n, r; + cin >> n >> r; + cout << binom(n, r) << '\n'; + } } \ No newline at end of file diff --git a/src/6-math/catalan_number_derangement_number.cpp b/src/6-math/catalan_number_derangement_number.cpp index 791229d..7c18ae0 100644 --- a/src/6-math/catalan_number_derangement_number.cpp +++ b/src/6-math/catalan_number_derangement_number.cpp @@ -5,26 +5,26 @@ const int MOD = 1e9 + 7; const int MAXN = 2020202; ll fac[MAXN], inv[MAXN], facInv[MAXN]; ll catalanNumber(int n) { // Cn = 2nCn / (n + 1) = (2n)! / (n!(n + 1)!) - return fac[2 * n] * facInv[n] % MOD * facInv[n + 1] % MOD; + return fac[2 * n] * facInv[n] % MOD * facInv[n + 1] % MOD; } int main() { - // Preprocessing in O(N) - fac[0] = fac[1] = inv[1] = 1; - facInv[0] = facInv[1] = 1; - for (int i = 2; i < MAXN; i++) { - fac[i] = i * fac[i - 1] % MOD; - inv[i] = -(MOD / i) * inv[MOD % i] % MOD; - if (inv[i] < 0) inv[i] += MOD; - facInv[i] = facInv[i - 1] * inv[i] % MOD; - } - // Answer each query in O(1) - int q; - cin >> q; - while (q--) { - int n; - cin >> n; - cout << catalanNumber(n) << '\n'; - } + // Preprocessing in O(N) + fac[0] = fac[1] = inv[1] = 1; + facInv[0] = facInv[1] = 1; + for (int i = 2; i < MAXN; i++) { + fac[i] = i * fac[i - 1] % MOD; + inv[i] = -(MOD / i) * inv[MOD % i] % MOD; + if (inv[i] < 0) inv[i] += MOD; + facInv[i] = facInv[i - 1] * inv[i] % MOD; + } + // Answer each query in O(1) + int q; + cin >> q; + while (q--) { + int n; + cin >> n; + cout << catalanNumber(n) << '\n'; + } } // Derangement Number // Counting derangements of a set amounts to the hat-check problem, @@ -38,11 +38,11 @@ const int MOD = 1e9 + 7; const int MAX = 101010; ll dp[MAX]; int main() { - dp[1] = 0, dp[2] = 1; - for (int i = 3; i < MAX; i++) { - dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2]) % MOD; - } - int n; - cin >> n; - cout << dp[n]; + dp[1] = 0, dp[2] = 1; + for (int i = 3; i < MAX; i++) { + dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2]) % MOD; + } + int n; + cin >> n; + cout << dp[n]; } \ No newline at end of file diff --git a/src/6-math/chinese_remainder_theorem.cpp b/src/6-math/chinese_remainder_theorem.cpp index 03e48cc..6bdbbf9 100644 --- a/src/6-math/chinese_remainder_theorem.cpp +++ b/src/6-math/chinese_remainder_theorem.cpp @@ -4,13 +4,13 @@ // OUTPUT: Solve a system of linear congruence, x = p (mod M), x = q (mod N). // TIME COMPLEXITY: O(log(max(M, N))) ll gcd(ll x, ll y) { - if (!y) return x; - return gcd(y, x % y); + if (!y) return x; + return gcd(y, x % y); } ll minv(ll x, ll y) { - if (x == 0 && y == 1) return 0; - if (x == 1) return 1; - return y - minv(y % x, x) * y / x; + if (x == 0 && y == 1) return 0; + if (x == 1) return 1; + return y - minv(y % x, x) * y / x; } // x = U.fr (mod U.sc) @@ -18,41 +18,41 @@ ll minv(ll x, ll y) { // returns solutions as x = ret.fr (mod ret.sc) // if no solution, returns { -1, -1 } pll crt(pll U, pll V) { - if (U.sc == -1 || V.sc == -1) return {-1, -1}; - if (U.sc == 1) return V; - if (V.sc == 1) return U; - ll g = gcd(U.sc, V.sc); - ll l = U.sc * V.sc / g; - // (U and V have a solution) iff (U.fr = U.sc (mod gcd(U.sc,V.sc))) - // also the solution is unique in the range [0, lcm(U.sc,V.sc)). - if ((V.fr - U.fr) % g) return {-1, -1}; + if (U.sc == -1 || V.sc == -1) return {-1, -1}; + if (U.sc == 1) return V; + if (V.sc == 1) return U; + ll g = gcd(U.sc, V.sc); + ll l = U.sc * V.sc / g; + // (U and V have a solution) iff (U.fr = U.sc (mod gcd(U.sc,V.sc))) + // also the solution is unique in the range [0, lcm(U.sc,V.sc)). + if ((V.fr - U.fr) % g) return {-1, -1}; - ll u = U.sc / g, v = V.sc / g; - ll mul = (V.fr - U.fr) / g; - mul = mul * minv(u % v, v) % v; + ll u = U.sc / g, v = V.sc / g; + ll mul = (V.fr - U.fr) / g; + mul = mul * minv(u % v, v) % v; - pll ret = {mul * U.sc + U.fr, l}; - ret.fr %= ret.sc, ret.fr = (ret.fr + ret.sc) % ret.sc; - return ret; + pll ret = {mul * U.sc + U.fr, l}; + ret.fr %= ret.sc, ret.fr = (ret.fr + ret.sc) % ret.sc; + return ret; } pll solvingSystemOfLinearCongruence(const vector &a) { - if (a.size() == 1) return a[0]; - pll ret = crt(a[0], a[1]); - for (int i = 2; i < a.size(); i++) ret = crt(ret, a[i]); - return ret; + if (a.size() == 1) return a[0]; + pll ret = crt(a[0], a[1]); + for (int i = 2; i < a.size(); i++) ret = crt(ret, a[i]); + return ret; } int main() { - int tc; - cin >> tc; - while (tc--) { - ll M, N, p, q; - cin >> M >> N >> p >> q; - p--, q--; // from the given input, 1 <= p <= M, 1 <= q <= N - vector cg; - cg.push_back({p, M}); - cg.push_back({q, N}); - pll ans = solvingSystemOfLinearCongruence(cg); - cout << (ans.fr == -1 ? ans.fr : ans.fr + 1) << '\n'; - } + int tc; + cin >> tc; + while (tc--) { + ll M, N, p, q; + cin >> M >> N >> p >> q; + p--, q--; // from the given input, 1 <= p <= M, 1 <= q <= N + vector cg; + cg.push_back({p, M}); + cg.push_back({q, N}); + pll ans = solvingSystemOfLinearCongruence(cg); + cout << (ans.fr == -1 ? ans.fr : ans.fr + 1) << '\n'; + } } \ No newline at end of file diff --git a/src/6-math/euclidean_algorithms.cpp b/src/6-math/euclidean_algorithms.cpp index daf9354..4a1e60b 100644 --- a/src/6-math/euclidean_algorithms.cpp +++ b/src/6-math/euclidean_algorithms.cpp @@ -2,11 +2,11 @@ // GCD, LCM ll gcd(ll a, ll b) { - if (b == 0) return a; - else return gcd(b, a % b); + if (b == 0) return a; + else return gcd(b, a % b); } ll lcm(ll a, ll b) { - return a * b / gcd(a, b); + return a * b / gcd(a, b); } // Extended GCD @@ -43,37 +43,37 @@ ll lcm(ll a, ll b) { // BOJ 14565 AC Code // https://www.acmicpc.net/problem/14565 pair egcd(ll a, ll b) { - ll s = 0, olds = 1; - ll t = 1, oldt = 0; - ll r = b, oldr = a; - while (r != 0) { - ll q = oldr / r; - ll tmp = oldr - q * r; - oldr = r, r = tmp; - tmp = olds - q * s; - olds = s, s = tmp; - tmp = oldt - q * t; - oldt = t, t = tmp; - } - // a * olds + b * oldt = d - // oldr = gcd(a, b) - return {{olds, oldt}, oldr}; + ll s = 0, olds = 1; + ll t = 1, oldt = 0; + ll r = b, oldr = a; + while (r != 0) { + ll q = oldr / r; + ll tmp = oldr - q * r; + oldr = r, r = tmp; + tmp = olds - q * s; + olds = s, s = tmp; + tmp = oldt - q * t; + oldt = t, t = tmp; + } + // a * olds + b * oldt = d + // oldr = gcd(a, b) + return {{olds, oldt}, oldr}; } ll linearCongruence(ll a, ll b, ll n) { // Find x such that ax = b (mod n). - pair res = egcd(a, n); - ll g = res.sc; - // ax + ny = b has a solution iff gcd(a,n) | b. - if (b % g) return -1; - return (res.fr.fr * (b / g) % n + n) % n; + pair res = egcd(a, n); + ll g = res.sc; + // ax + ny = b has a solution iff gcd(a,n) | b. + if (b % g) return -1; + return (res.fr.fr * (b / g) % n + n) % n; } ll modInv(ll a, ll p) { // Find x such that ax = 1 (mod p). - pair res = egcd(a, p); - // Modular inverse exists iff gcd(a, p) = 1. - if (res.sc == 1) return (res.fr.fr + p) % p; - else return -1; + pair res = egcd(a, p); + // Modular inverse exists iff gcd(a, p) = 1. + if (res.sc == 1) return (res.fr.fr + p) % p; + else return -1; } int main() { - ll N, A; - cin >> N >> A; - cout << N - A << ' ' << modInv(A, N); + ll N, A; + cin >> N >> A; + cout << N - A << ' ' << modInv(A, N); } \ No newline at end of file diff --git a/src/6-math/eulers_phi_function.cpp b/src/6-math/eulers_phi_function.cpp index 1d65a72..20647c0 100644 --- a/src/6-math/eulers_phi_function.cpp +++ b/src/6-math/eulers_phi_function.cpp @@ -4,27 +4,27 @@ // OUTPUT: Find the number of natural numbers 1 ≤ k ≤ n such that GCD(n, k) = 1. // TIME COMPLEXITY: O(sqrt(n)) ll phi(ll x) { // Find phi(x) in O(sqrt(x)). - vector p; - // Factorization in O(sqrt(x)). - for (ll i = 2; i <= sqrt(x); i++) { - ll res = 1; - while (x % i == 0) { - x /= i, res *= i; + vector p; + // Factorization in O(sqrt(x)). + for (ll i = 2; i <= sqrt(x); i++) { + ll res = 1; + while (x % i == 0) { + x /= i, res *= i; + } + if (res > 1) p.push_back({res, i}); } - if (res > 1) p.push_back({res, i}); - } - if (x > 1) p.push_back({x, x}); - // Find phi(x). - // phi(p^k) = p^{k-1} * (p - 1) for any prime number p. - // phi(mn) = phi(m) * phi(n) if gcd(m, n) = 1 - ll ret = 1; - for (auto &i : p) { - ret *= (i.fr / i.sc) * (i.sc - 1); - } - return ret; + if (x > 1) p.push_back({x, x}); + // Find phi(x). + // phi(p^k) = p^{k-1} * (p - 1) for any prime number p. + // phi(mn) = phi(m) * phi(n) if gcd(m, n) = 1 + ll ret = 1; + for (auto &i : p) { + ret *= (i.fr / i.sc) * (i.sc - 1); + } + return ret; } int main() { - ll n; - cin >> n; - cout << phi(n); + ll n; + cin >> n; + cout << phi(n); } \ No newline at end of file diff --git a/src/6-math/fft.cpp b/src/6-math/fft.cpp index 7c75d35..44ab56c 100644 --- a/src/6-math/fft.cpp +++ b/src/6-math/fft.cpp @@ -3,78 +3,78 @@ namespace fft { using real_t = double; using cpx = complex; void FFT(vector &a, bool inv_fft = false) { - int N = a.size(); - vector root(N / 2); - for (int i = 1, j = 0; i < N; i++) { - int bit = (N >> 1); - while (j >= bit) j -= bit, bit >>= 1; - j += bit; - if (i < j) swap(a[i], a[j]); - } - real_t ang = 2 * acos(-1) / N * (inv_fft ? -1 : 1); - for (int i = 0; i < N / 2; i++) root[i] = cpx(cos(ang * i), sin(ang * i)); - /* - XOR Convolution : set roots[*] = 1. - OR Convolution : set roots[*] = 1, and do following: - if (!inv) a[j + k] = u + v, a[j + k + i/2] = u; - else a[j + k] = v, a[j + k + i/2] = u - v; - */ - for (int i = 2; i <= N; i <<= 1) { - int step = N / i; - for (int j = 0; j < N; j += i) - for (int k = 0; k < i / 2; k++) { - cpx u = a[j + k], v = a[j + k + i / 2] * root[step * k]; - a[j + k] = u + v; - a[j + k + i / 2] = u - v; - } - } - if (inv_fft) - for (int i = 0; i < N; i++) a[i] /= N; // skip for OR convolution. + int N = a.size(); + vector root(N / 2); + for (int i = 1, j = 0; i < N; i++) { + int bit = (N >> 1); + while (j >= bit) j -= bit, bit >>= 1; + j += bit; + if (i < j) swap(a[i], a[j]); + } + real_t ang = 2 * acos(-1) / N * (inv_fft ? -1 : 1); + for (int i = 0; i < N / 2; i++) root[i] = cpx(cos(ang * i), sin(ang * i)); + /* + XOR Convolution : set roots[*] = 1. + OR Convolution : set roots[*] = 1, and do following: + if (!inv) a[j + k] = u + v, a[j + k + i/2] = u; + else a[j + k] = v, a[j + k + i/2] = u - v; + */ + for (int i = 2; i <= N; i <<= 1) { + int step = N / i; + for (int j = 0; j < N; j += i) + for (int k = 0; k < i / 2; k++) { + cpx u = a[j + k], v = a[j + k + i / 2] * root[step * k]; + a[j + k] = u + v; + a[j + k + i / 2] = u - v; + } + } + if (inv_fft) + for (int i = 0; i < N; i++) a[i] /= N; // skip for OR convolution. } vector multiply(const vector &_a, const vector &_b) { - vector a(all(_a)), b(all(_b)); - int N = 2; - while (N < a.size() + b.size()) N <<= 1; - a.resize(N); - b.resize(N); - FFT(a); - FFT(b); - for (int i = 0; i < N; i++) a[i] *= b[i]; - FFT(a, 1); - vector ret(N); - for (int i = 0; i < N; i++) ret[i] = llround(a[i].real()); - return ret; + vector a(all(_a)), b(all(_b)); + int N = 2; + while (N < a.size() + b.size()) N <<= 1; + a.resize(N); + b.resize(N); + FFT(a); + FFT(b); + for (int i = 0; i < N; i++) a[i] *= b[i]; + FFT(a, 1); + vector ret(N); + for (int i = 0; i < N; i++) ret[i] = llround(a[i].real()); + return ret; } vector multiply_mod(const vector &a, const vector &b, const ull mod) { - int N = 2; - while (N < a.size() + b.size()) N <<= 1; - vector v1(N), v2(N), r1(N), r2(N); - for (int i = 0; i < a.size(); i++) v1[i] = cpx(a[i] >> 15, a[i] & 32767); - for (int i = 0; i < b.size(); i++) v2[i] = cpx(b[i] >> 15, b[i] & 32767); - FFT(v1); - FFT(v2); - for (int i = 0; i < N; i++) { - int j = i ? N - i : i; - cpx ans1 = (v1[i] + conj(v1[j])) * cpx(0.5, 0); - cpx ans2 = (v1[i] - conj(v1[j])) * cpx(0, -0.5); - cpx ans3 = (v2[i] + conj(v2[j])) * cpx(0.5, 0); - cpx ans4 = (v2[i] - conj(v2[j])) * cpx(0, -0.5); - r1[i] = (ans1 * ans3) + (ans1 * ans4) * cpx(0, 1); - r2[i] = (ans2 * ans3) + (ans2 * ans4) * cpx(0, 1); - } - FFT(r1, true); - FFT(r2, true); - vector ret(N); - for (int i = 0; i < N; i++) { - ll av = llround(r1[i].real()) % mod; - ll bv = (llround(r1[i].imag()) + llround(r2[i].real())) % mod; - ll cv = llround(r2[i].imag()) % mod; - ret[i] = (av << 30) + (bv << 15) + cv; - ret[i] %= mod; - ret[i] += mod; - ret[i] %= mod; - } - return ret; + int N = 2; + while (N < a.size() + b.size()) N <<= 1; + vector v1(N), v2(N), r1(N), r2(N); + for (int i = 0; i < a.size(); i++) v1[i] = cpx(a[i] >> 15, a[i] & 32767); + for (int i = 0; i < b.size(); i++) v2[i] = cpx(b[i] >> 15, b[i] & 32767); + FFT(v1); + FFT(v2); + for (int i = 0; i < N; i++) { + int j = i ? N - i : i; + cpx ans1 = (v1[i] + conj(v1[j])) * cpx(0.5, 0); + cpx ans2 = (v1[i] - conj(v1[j])) * cpx(0, -0.5); + cpx ans3 = (v2[i] + conj(v2[j])) * cpx(0.5, 0); + cpx ans4 = (v2[i] - conj(v2[j])) * cpx(0, -0.5); + r1[i] = (ans1 * ans3) + (ans1 * ans4) * cpx(0, 1); + r2[i] = (ans2 * ans3) + (ans2 * ans4) * cpx(0, 1); + } + FFT(r1, true); + FFT(r2, true); + vector ret(N); + for (int i = 0; i < N; i++) { + ll av = llround(r1[i].real()) % mod; + ll bv = (llround(r1[i].imag()) + llround(r2[i].real())) % mod; + ll cv = llround(r2[i].imag()) % mod; + ret[i] = (av << 30) + (bv << 15) + cv; + ret[i] %= mod; + ret[i] += mod; + ret[i] %= mod; + } + return ret; } } // namespace fft namespace ntt { @@ -82,43 +82,43 @@ constexpr ll MOD = (119 << 23) + 1, root = 3; // = 998244353 // For p < 2^30 there is also e.g. 5 << 25, 7 << 26, 479 << 21 // and 483 << 21 (same root). The last two are > 10^9. ll modpow(ll b, ll e) { - ll ans = 1; - for (; e; b = b * b % MOD, e /= 2) - if (e & 1) ans = ans * b % MOD; - return ans; + ll ans = 1; + for (; e; b = b * b % MOD, e /= 2) + if (e & 1) ans = ans * b % MOD; + return ans; } void ntt(vector &a) { - int n = sz(a), L = 31 - __builtin_clz(n); - static vector rt(2, 1); - for (static int k = 2, s = 2; k < n; k *= 2, s++) { - rt.resize(n); - ll z[] = {1, modpow(root, MOD >> s)}; - for (int i = k; i < 2 * k; i++) - rt[i] = rt[i / 2] * z[i & 1] % MOD; - } - vector rev(n); - for (int i = 0; i < n; i++) rev[i] = (rev[i / 2] | (i & 1) << L) / 2; - for (int i = 0; i < n; i++) - if (i < rev[i]) swap(a[i], a[rev[i]]); - for (int k = 1; k < n; k *= 2) - for (int i = 0; i < n; i += 2 * k) - for (int j = 0; j < k; j++) { - ll z = rt[j + k] * a[i + j + k] % MOD, &ai = a[i + j]; - a[i + j + k] = ai - z + (z > ai ? MOD : 0); - ai += (ai + z >= MOD ? z - MOD : z); - } + int n = sz(a), L = 31 - __builtin_clz(n); + static vector rt(2, 1); + for (static int k = 2, s = 2; k < n; k *= 2, s++) { + rt.resize(n); + ll z[] = {1, modpow(root, MOD >> s)}; + for (int i = k; i < 2 * k; i++) + rt[i] = rt[i / 2] * z[i & 1] % MOD; + } + vector rev(n); + for (int i = 0; i < n; i++) rev[i] = (rev[i / 2] | (i & 1) << L) / 2; + for (int i = 0; i < n; i++) + if (i < rev[i]) swap(a[i], a[rev[i]]); + for (int k = 1; k < n; k *= 2) + for (int i = 0; i < n; i += 2 * k) + for (int j = 0; j < k; j++) { + ll z = rt[j + k] * a[i + j + k] % MOD, &ai = a[i + j]; + a[i + j + k] = ai - z + (z > ai ? MOD : 0); + ai += (ai + z >= MOD ? z - MOD : z); + } } vector multiply(const vector &a, const vector &b) { - if (a.empty() || b.empty()) return {}; - int s = sz(a) + sz(b) - 1, B = 32 - __builtin_clz(s), - n = 1 << B; - int inv = modpow(n, MOD - 2); - vector L(a), R(b), out(n); - L.resize(n), R.resize(n); - ntt(L), ntt(R); - for (int i = 0; i < n; i++) - out[-i & (n - 1)] = (ll)L[i] * R[i] % MOD * inv % MOD; - ntt(out); - return {out.begin(), out.begin() + s}; + if (a.empty() || b.empty()) return {}; + int s = sz(a) + sz(b) - 1, B = 32 - __builtin_clz(s), + n = 1 << B; + int inv = modpow(n, MOD - 2); + vector L(a), R(b), out(n); + L.resize(n), R.resize(n); + ntt(L), ntt(R); + for (int i = 0; i < n; i++) + out[-i & (n - 1)] = (ll)L[i] * R[i] % MOD * inv % MOD; + ntt(out); + return {out.begin(), out.begin() + s}; } } // namespace ntt \ No newline at end of file diff --git a/src/6-math/gauss_jordan_elimination.cpp b/src/6-math/gauss_jordan_elimination.cpp index 46185d8..b070914 100644 --- a/src/6-math/gauss_jordan_elimination.cpp +++ b/src/6-math/gauss_jordan_elimination.cpp @@ -2,92 +2,92 @@ // Inverse Matrix void inverse_matrix(vector> &a) { - int n = a.size(); - int m = n + n; - for (int i = 0; i < n; ++i) - for (int j = 0; j < n; ++j) - a[i].push_back(i == j); - for (int c = 0, r = 0; c < m && r < n; ++c) { - int p = r; // pivot row - for (int i = r; i < n; ++i) - if (a[p][c] < a[i][c]) - p = i; - if (a[p][c] == 0) { - puts("no inverse"); - return; - }; - for (int j = 0; j < m; ++j) - swap(a[p][j], a[r][j]); - double t = a[r][c]; - for (int j = 0; j < m; ++j) - a[r][j] /= t; + int n = a.size(); + int m = n + n; for (int i = 0; i < n; ++i) - if (i != r) { - double t = a[i][c]; - for (int j = c; j < m; ++j) - a[i][j] -= a[r][j] * t; - } - ++r; - } - for (int i = 0; i < n; ++i, puts("")) - for (int j = 0; j < n; ++j) - printf("%lf ", a[i][n + j]); + for (int j = 0; j < n; ++j) + a[i].push_back(i == j); + for (int c = 0, r = 0; c < m && r < n; ++c) { + int p = r; // pivot row + for (int i = r; i < n; ++i) + if (a[p][c] < a[i][c]) + p = i; + if (a[p][c] == 0) { + puts("no inverse"); + return; + }; + for (int j = 0; j < m; ++j) + swap(a[p][j], a[r][j]); + double t = a[r][c]; + for (int j = 0; j < m; ++j) + a[r][j] /= t; + for (int i = 0; i < n; ++i) + if (i != r) { + double t = a[i][c]; + for (int j = c; j < m; ++j) + a[i][j] -= a[r][j] * t; + } + ++r; + } + for (int i = 0; i < n; ++i, puts("")) + for (int j = 0; j < n; ++j) + printf("%lf ", a[i][n + j]); } // Gauss-Jordan Elimination modulo p vector gauss_mod(vector> &a, int mod) { - vector inv(mod); // modulo inverse 전처리 - inv[1] = 1; - for (int i = 2; i < mod; ++i) - inv[i] = mod - (mod / i) * inv[mod % i] % mod; - int n = a.size(); - int m = a[0].size(); - vector w(m, -1); // i번째 열에 있는 pivot이 몇 번째 행에 있는지 저장 - for (int c = 0, r = 0; c < m && r < n; ++c) { - int p = r; // pivot row - for (int i = r; i < n; ++i) - if (a[p][c] < a[i][c]) - p = i; - if (a[p][c] == 0) continue; // free variable - for (int j = 0; j < m; ++j) - swap(a[p][j], a[r][j]); - w[c] = r; - int t = a[r][c]; - for (int j = 0; j < m; ++j) - a[r][j] = a[r][j] * inv[t] % mod; - for (int i = 0; i < n; ++i) - if (i != r) { - int t = a[i][c]; - for (int j = c; j < m; ++j) - a[i][j] = (a[i][j] - a[r][j] * t % mod + mod) % mod; - } - ++r; - } - for (int i = 0; i < n; ++i) // existence of solution - if (count(a[i].begin(), --a[i].end(), 0) == m - 1 && a[i][m - 1]) - return vector(); // no solution - vector ans(m); - for (int i = 0; i < m; ++i) - if (~w[i]) ans[i] = a[w[i]][m - 1]; - return ans; // solution exist + vector inv(mod); // modulo inverse 전처리 + inv[1] = 1; + for (int i = 2; i < mod; ++i) + inv[i] = mod - (mod / i) * inv[mod % i] % mod; + int n = a.size(); + int m = a[0].size(); + vector w(m, -1); // i번째 열에 있는 pivot이 몇 번째 행에 있는지 저장 + for (int c = 0, r = 0; c < m && r < n; ++c) { + int p = r; // pivot row + for (int i = r; i < n; ++i) + if (a[p][c] < a[i][c]) + p = i; + if (a[p][c] == 0) continue; // free variable + for (int j = 0; j < m; ++j) + swap(a[p][j], a[r][j]); + w[c] = r; + int t = a[r][c]; + for (int j = 0; j < m; ++j) + a[r][j] = a[r][j] * inv[t] % mod; + for (int i = 0; i < n; ++i) + if (i != r) { + int t = a[i][c]; + for (int j = c; j < m; ++j) + a[i][j] = (a[i][j] - a[r][j] * t % mod + mod) % mod; + } + ++r; + } + for (int i = 0; i < n; ++i) // existence of solution + if (count(a[i].begin(), --a[i].end(), 0) == m - 1 && a[i][m - 1]) + return vector(); // no solution + vector ans(m); + for (int i = 0; i < m; ++i) + if (~w[i]) ans[i] = a[w[i]][m - 1]; + return ans; // solution exist } // Gauss-Jordan Elimination modulo 2 const int sz = 500; bitset gauss_bit(vector> &a) { - int n = a.size(); - int m = a[0].size(); - vector w(m, -1); - for (int c = 0, r = 0; c < m && r < n; ++c) { - for (int i = r; i < n; ++i) - if (a[i][c]) { - swap(a[i], a[r]); - break; - } - if (a[r][c] == 0) continue; - w[c] = r; - for (int i = 0; i < n; ++i) - if (i != r) - if (a[i][c]) a[i] ^= a[r]; - ++r; - } - // .. same + int n = a.size(); + int m = a[0].size(); + vector w(m, -1); + for (int c = 0, r = 0; c < m && r < n; ++c) { + for (int i = r; i < n; ++i) + if (a[i][c]) { + swap(a[i], a[r]); + break; + } + if (a[r][c] == 0) continue; + w[c] = r; + for (int i = 0; i < n; ++i) + if (i != r) + if (a[i][c]) a[i] ^= a[r]; + ++r; + } + // .. same } \ No newline at end of file diff --git a/src/6-math/matrix.cpp b/src/6-math/matrix.cpp index f5ee35a..0fbb2d5 100644 --- a/src/6-math/matrix.cpp +++ b/src/6-math/matrix.cpp @@ -2,41 +2,41 @@ const int MOD = 1e9 + 7; struct Matrix { - vector> a; - Matrix operator*(const Matrix &rhs) const { - Matrix ret; - ret.a.resize(sz(a), vector(sz(rhs.a[0]))); - for (int y = 0; y < sz(ret.a); y++) { - for (int x = 0; x < sz(ret.a[y]); x++) { - ll sum = 0; - for (int i = 0; i < sz(a[y]); i++) { - sum = (sum + a[y][i] * rhs.a[i][x]) % MOD; + vector> a; + Matrix operator*(const Matrix &rhs) const { + Matrix ret; + ret.a.resize(sz(a), vector(sz(rhs.a[0]))); + for (int y = 0; y < sz(ret.a); y++) { + for (int x = 0; x < sz(ret.a[y]); x++) { + ll sum = 0; + for (int i = 0; i < sz(a[y]); i++) { + sum = (sum + a[y][i] * rhs.a[i][x]) % MOD; + } + ret.a[y][x] = sum; + } } - ret.a[y][x] = sum; - } + return ret; } - return ret; - } }; Matrix matrixPower(const Matrix &val, ll exp) { - if (exp == 1) return val; - Matrix res = matrixPower(val, exp / 2); - Matrix ret = res * res; - if (exp & 1) ret = ret * val; - return ret; + if (exp == 1) return val; + Matrix res = matrixPower(val, exp / 2); + Matrix ret = res * res; + if (exp & 1) ret = ret * val; + return ret; } int main() { - ll n; - cin >> n; - if (n == 1) { - cout << 1; - return 0; - } - // Base Matrix - Matrix base; - base.a.resize(2, vector(2)); - base.a[0][0] = base.a[0][1] = base.a[1][0] = 1; - // Matrix Exponentiation - Matrix ans = matrixPower(base, n - 1); - cout << ans.a[0][0]; + ll n; + cin >> n; + if (n == 1) { + cout << 1; + return 0; + } + // Base Matrix + Matrix base; + base.a.resize(2, vector(2)); + base.a[0][0] = base.a[0][1] = base.a[1][0] = 1; + // Matrix Exponentiation + Matrix ans = matrixPower(base, n - 1); + cout << ans.a[0][0]; } \ No newline at end of file diff --git a/src/6-math/miller_rabin_pollard_rho.cpp b/src/6-math/miller_rabin_pollard_rho.cpp index 7923a1a..6ae2131 100644 --- a/src/6-math/miller_rabin_pollard_rho.cpp +++ b/src/6-math/miller_rabin_pollard_rho.cpp @@ -3,67 +3,67 @@ namespace miller_rabin { ll mul(ll x, ll y, ll mod) { return (__int128_t)x * y % mod; } ll ipow(ll x, ll y, ll p) { - ll ret = 1, piv = x % p; - while (y) { - if (y & 1) ret = mul(ret, piv, p); - piv = mul(piv, piv, p); - y >>= 1; - } - return ret; + ll ret = 1, piv = x % p; + while (y) { + if (y & 1) ret = mul(ret, piv, p); + piv = mul(piv, piv, p); + y >>= 1; + } + return ret; } bool miller_rabin(ll x, ll a) { - if (x % a == 0) return 0; - ll d = x - 1; - while (1) { - ll tmp = ipow(a, d, x); - if (d & 1) return (tmp != 1 && tmp != x - 1); - else if (tmp == x - 1) return 0; - d >>= 1; - } + if (x % a == 0) return 0; + ll d = x - 1; + while (1) { + ll tmp = ipow(a, d, x); + if (d & 1) return (tmp != 1 && tmp != x - 1); + else if (tmp == x - 1) return 0; + d >>= 1; + } } bool isprime(ll x) { - for (auto &i : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) { - if (x == i) return 1; - if (x > 40 && miller_rabin(x, i)) return 0; - } - if (x <= 40) return 0; - return 1; + for (auto &i : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) { + if (x == i) return 1; + if (x > 40 && miller_rabin(x, i)) return 0; + } + if (x <= 40) return 0; + return 1; } }; // namespace miller_rabin namespace pollard_rho { ll f(ll x, ll n, ll c) { - return (c + miller_rabin::mul(x, x, n)) % n; + return (c + miller_rabin::mul(x, x, n)) % n; } void rec(ll n, vector &v) { - if (n == 1) return; - if (n % 2 == 0) { - v.push_back(2); - rec(n / 2, v); - return; - } - if (miller_rabin::isprime(n)) { - v.push_back(n); - return; - } - ll a, b, c; - while (1) { - a = rand() % (n - 2) + 2; - b = a; - c = rand() % 20 + 1; - do { - a = f(a, n, c); - b = f(f(b, n, c), n, c); - } while (gcd(abs(a - b), n) == 1); - if (a != b) break; - } - ll x = gcd(abs(a - b), n); - rec(x, v); - rec(n / x, v); + if (n == 1) return; + if (n % 2 == 0) { + v.push_back(2); + rec(n / 2, v); + return; + } + if (miller_rabin::isprime(n)) { + v.push_back(n); + return; + } + ll a, b, c; + while (1) { + a = rand() % (n - 2) + 2; + b = a; + c = rand() % 20 + 1; + do { + a = f(a, n, c); + b = f(f(b, n, c), n, c); + } while (gcd(abs(a - b), n) == 1); + if (a != b) break; + } + ll x = gcd(abs(a - b), n); + rec(x, v); + rec(n / x, v); } vector factorize(ll n) { - vector ret; - rec(n, ret); - sort(ret.begin(), ret.end()); - return ret; + vector ret; + rec(n, ret); + sort(ret.begin(), ret.end()); + return ret; } }; // namespace pollard_rho \ No newline at end of file diff --git a/src/6-math/mobius.cpp b/src/6-math/mobius.cpp index 310a644..435adde 100644 --- a/src/6-math/mobius.cpp +++ b/src/6-math/mobius.cpp @@ -1,21 +1,21 @@ #include "../common/common.hpp" vector mobius(int n) { - vector mu(n + 1, 1), prime, lp(n + 1, 0); - mu[0] = 0; - for (int i = 2; i <= n; i++) { - if (!lp[i]) { - lp[i] = i, prime.push_back(i), mu[i] = -1; + vector mu(n + 1, 1), prime, lp(n + 1, 0); + mu[0] = 0; + for (int i = 2; i <= n; i++) { + if (!lp[i]) { + lp[i] = i, prime.push_back(i), mu[i] = -1; + } + for (auto &p : prime) { + ll v = 1LL * p * i; + if (v > n) break; + lp[v] = p; + if (lp[i] = p) { + mu[v] = 0; + break; + } else mu[v] = -mu[i]; + } } - for (auto &p : prime) { - ll v = 1LL * p * i; - if (v > n) break; - lp[v] = p; - if (lp[i] = p) { - mu[v] = 0; - break; - } else mu[v] = -mu[i]; - } - } - return mu; + return mu; } diff --git a/src/6-math/sieve.cpp b/src/6-math/sieve.cpp index c96bf79..6621769 100644 --- a/src/6-math/sieve.cpp +++ b/src/6-math/sieve.cpp @@ -6,15 +6,15 @@ const int MAX = 1e6; bool isPrime[MAX + 1]; vector prime(1, 2); void getPrime() { - fill(isPrime + 2, isPrime + MAX + 1, 1); - for (ll i = 4; i <= MAX; i += 2) - isPrime[i] = 0; - for (ll i = 3; i <= MAX; i += 2) { - if (!isPrime[i]) continue; - prime.push_back(i); - for (ll j = i * i; j <= MAX; j += i * 2) - isPrime[j] = 0; - } + fill(isPrime + 2, isPrime + MAX + 1, 1); + for (ll i = 4; i <= MAX; i += 2) + isPrime[i] = 0; + for (ll i = 3; i <= MAX; i += 2) { + if (!isPrime[i]) continue; + prime.push_back(i); + for (ll j = i * i; j <= MAX; j += i * 2) + isPrime[j] = 0; + } } // Linear Sieve @@ -23,33 +23,33 @@ vector sp(MAXN + 1); vector prime; // Determine prime numbers between 1 and MAXN in O(MAXN) void linearSieve() { - for (int i = 2; i <= MAXN; i++) { - if (!sp[i]) { - prime.push_back(i); - sp[i] = i; - } - for (auto j : prime) { - if (i * j > MAXN) break; - sp[i * j] = j; - if (i % j == 0) break; + for (int i = 2; i <= MAXN; i++) { + if (!sp[i]) { + prime.push_back(i); + sp[i] = i; + } + for (auto j : prime) { + if (i * j > MAXN) break; + sp[i * j] = j; + if (i % j == 0) break; + } } - } } // factorization in O(log x) void factorization(int x) { - while (x > 1) { - cout << sp[x] << ' '; - x /= sp[x]; - } - cout << '\n'; + while (x > 1) { + cout << sp[x] << ' '; + x /= sp[x]; + } + cout << '\n'; } int main() { - linearSieve(); - int n; - cin >> n; - while (n--) { - int x; - cin >> x; - factorization(x); - } + linearSieve(); + int n; + cin >> n; + while (n--) { + int x; + cin >> x; + factorization(x); + } } \ No newline at end of file diff --git a/src/7-misc/dp_opt.cpp b/src/7-misc/dp_opt.cpp index 3dd0643..2f50fad 100644 --- a/src/7-misc/dp_opt.cpp +++ b/src/7-misc/dp_opt.cpp @@ -6,47 +6,47 @@ // Naive Complexity: O(n^2) // Optimized Complexity: O(nlogn) (if a[i] <= a[i + 1], it can also be done in O(n)) struct Line { // f(x) = px + q, x >= s - ll p, q; - double s; - Line() : Line(1, 0) {} - Line(ll sp, ll sq) : p(sp), q(sq), s(0) {} + ll p, q; + double s; + Line() : Line(1, 0) {} + Line(ll sp, ll sq) : p(sp), q(sq), s(0) {} }; double cross(const Line &u, const Line &v) { - return (double)(v.q - u.q) / (u.p - v.p); + return (double)(v.q - u.q) / (u.p - v.p); } int n; ll a[101010], b[101010]; ll dp[101010]; Line ch[101010]; void input() { - cin >> n; - for (int i = 1; i <= n; i++) cin >> a[i]; - for (int i = 1; i <= n; i++) cin >> b[i]; + cin >> n; + for (int i = 1; i <= n; i++) cin >> a[i]; + for (int i = 1; i <= n; i++) cin >> b[i]; } void convexHullTrick() { - int top = 1; - for (int i = 2; i <= n; i++) { - Line g(b[i - 1], dp[i - 1]); - while (top > 1) { - g.s = cross(ch[top - 1], g); - if (ch[top - 1].s < g.s) break; - --top; - } - ch[top++] = g; - int l = 1, r = top - 1; - while (l < r) { - int mid = (l + r + 1) >> 1; - if (a[i] < ch[mid].s) r = mid - 1; - else l = mid; + int top = 1; + for (int i = 2; i <= n; i++) { + Line g(b[i - 1], dp[i - 1]); + while (top > 1) { + g.s = cross(ch[top - 1], g); + if (ch[top - 1].s < g.s) break; + --top; + } + ch[top++] = g; + int l = 1, r = top - 1; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (a[i] < ch[mid].s) r = mid - 1; + else l = mid; + } + int fpos = l; + dp[i] = ch[fpos].p * a[i] + ch[fpos].q; } - int fpos = l; - dp[i] = ch[fpos].p * a[i] + ch[fpos].q; - } } int main() { - input(); - convexHullTrick(); - cout << dp[n]; + input(); + convexHullTrick(); + cout << dp[n]; } // 2. Knuth Optimization @@ -62,34 +62,34 @@ const ll INF = 1e18; int n, opt[5050][5050]; ll a[5050], DP[5050][5050], psum[5050]; int main() { - int tc; - cin >> tc; - while (tc--) { - cin >> n; - for (int i = 1; i <= n; i++) { - cin >> a[i]; - psum[i] = a[i] + psum[i - 1]; - } - for (int i = 1; i <= n; i++) { - DP[i][i] = 0; - opt[i][i] = i; - } - for (int i = n - 1; i >= 1; i--) { - for (int j = i + 1; j <= n; j++) { - ll mn = INF, mnk = -1; - for (int k = opt[i][j - 1]; k <= opt[i + 1][j]; k++) { - ll res = DP[i][k] + DP[k + 1][j] + (psum[j] - psum[i - 1]); - if (res < mn) { - mn = res; - mnk = k; - } + int tc; + cin >> tc; + while (tc--) { + cin >> n; + for (int i = 1; i <= n; i++) { + cin >> a[i]; + psum[i] = a[i] + psum[i - 1]; + } + for (int i = 1; i <= n; i++) { + DP[i][i] = 0; + opt[i][i] = i; + } + for (int i = n - 1; i >= 1; i--) { + for (int j = i + 1; j <= n; j++) { + ll mn = INF, mnk = -1; + for (int k = opt[i][j - 1]; k <= opt[i + 1][j]; k++) { + ll res = DP[i][k] + DP[k + 1][j] + (psum[j] - psum[i - 1]); + if (res < mn) { + mn = res; + mnk = k; + } + } + DP[i][j] = mn; + opt[i][j] = mnk; + } } - DP[i][j] = mn; - opt[i][j] = mnk; - } + cout << DP[1][n] << '\n'; } - cout << DP[1][n] << '\n'; - } } // 3. Divide and Conquer Optimization @@ -102,35 +102,35 @@ int n, m; ll a[8080], psum[8080]; ll dp[808][8080]; void f(int gr, int l, int r, int nl, int nr) { - int mid = (l + r) >> 1, idx = -1; - ll &res = dp[gr][mid]; - res = INF; - for (int i = nl; i <= min(mid, nr); i++) { - assert(i <= mid); - ll val = dp[gr - 1][i] + (mid - i) * (psum[mid] - psum[i]); - if (res > val) { - res = val, idx = i; + int mid = (l + r) >> 1, idx = -1; + ll &res = dp[gr][mid]; + res = INF; + for (int i = nl; i <= min(mid, nr); i++) { + assert(i <= mid); + ll val = dp[gr - 1][i] + (mid - i) * (psum[mid] - psum[i]); + if (res > val) { + res = val, idx = i; + } + } + if (l < r) { + f(gr, l, mid, nl, idx); + f(gr, mid + 1, r, idx, nr); } - } - if (l < r) { - f(gr, l, mid, nl, idx); - f(gr, mid + 1, r, idx, nr); - } } int main() { - // input - cin >> n >> m; - for (int i = 1; i <= n; i++) cin >> a[i]; - // build prefix sum - for (int i = 1; i <= n; i++) - psum[i] = a[i] + psum[i - 1]; - // dp (dnc opt) - for (int i = 1; i <= n; i++) - dp[1][i] = i * psum[i]; - for (int i = 2; i <= m; i++) - f(i, 0, n, 0, n); - // output - cout << dp[m][n]; + // input + cin >> n >> m; + for (int i = 1; i <= n; i++) cin >> a[i]; + // build prefix sum + for (int i = 1; i <= n; i++) + psum[i] = a[i] + psum[i - 1]; + // dp (dnc opt) + for (int i = 1; i <= n; i++) + dp[1][i] = i * psum[i]; + for (int i = 2; i <= m; i++) + f(i, 0, n, 0, n); + // output + cout << dp[m][n]; } // 4. Slope Trick @@ -139,17 +139,17 @@ int main() { // The goal is the make the array strictly increasing by making the minimum possible number of operations. // TIME COMPLEXITY: O(n log(n)) ll slope_trick(vector a) { - ll ret = 0; - priority_queue pq; - for (int i = 0; i < sz(a); i++) { - a[i] -= i; // Change strictly increasing condition to non-decreasing condition - pq.push(a[i]); + ll ret = 0; + priority_queue pq; + for (int i = 0; i < sz(a); i++) { + a[i] -= i; // Change strictly increasing condition to non-decreasing condition + pq.push(a[i]); - if (pq.top() > a[i]) { - ret += pq.top() - a[i]; - pq.pop(); - pq.push(a[i]); + if (pq.top() > a[i]) { + ret += pq.top() - a[i]; + pq.pop(); + pq.push(a[i]); + } } - } - return ret; + return ret; } diff --git a/src/7-misc/fraction_data_type.cpp b/src/7-misc/fraction_data_type.cpp index 4acba91..2d39ccc 100644 --- a/src/7-misc/fraction_data_type.cpp +++ b/src/7-misc/fraction_data_type.cpp @@ -3,64 +3,64 @@ #define ll long long struct Fraction { - ll n, d; // represent n/d + ll n, d; // represent n/d - Fraction(ll N, ll D) { - n = N, d = D; - reduce(); - } - Fraction(ll N) { n = N, d = 1; } - Fraction() { n = 0, d = 1; } + Fraction(ll N, ll D) { + n = N, d = D; + reduce(); + } + Fraction(ll N) { n = N, d = 1; } + Fraction() { n = 0, d = 1; } - ll gcd(ll a, ll b) { - if (b == 0) return a; - else return gcd(b, a % b); - } - void reduce() { - // ll g = gcd(n, d); - // n /= g, d /= g; - if (d < 0) n *= -1, d *= -1; - } + ll gcd(ll a, ll b) { + if (b == 0) return a; + else return gcd(b, a % b); + } + void reduce() { + // ll g = gcd(n, d); + // n /= g, d /= g; + if (d < 0) n *= -1, d *= -1; + } - bool operator==(const Fraction &rhs) const { - return n * rhs.d == rhs.n * d; - } - bool operator!=(const Fraction &rhs) const { - return n * rhs.d != rhs.n * d; - } - bool operator<(const Fraction &rhs) const { - return n * rhs.d < rhs.n * d; - } - bool operator>(const Fraction &rhs) const { - return n * rhs.d > rhs.n * d; - } + bool operator==(const Fraction &rhs) const { + return n * rhs.d == rhs.n * d; + } + bool operator!=(const Fraction &rhs) const { + return n * rhs.d != rhs.n * d; + } + bool operator<(const Fraction &rhs) const { + return n * rhs.d < rhs.n * d; + } + bool operator>(const Fraction &rhs) const { + return n * rhs.d > rhs.n * d; + } - Fraction operator+(const Fraction &rhs) const { - Fraction ret; - ret.n = n * rhs.d + rhs.n * d; - ret.d = d * rhs.d; - ret.reduce(); - return ret; - } - Fraction operator-(const Fraction &rhs) const { - Fraction ret; - ret.n = n * rhs.d - rhs.n * d; - ret.d = d * rhs.d; - ret.reduce(); - return ret; - } - Fraction operator*(const Fraction &rhs) { - Fraction ret; - ret.n = n * rhs.n; - ret.d = d * rhs.d; - ret.reduce(); - return ret; - } - Fraction operator/(const Fraction &rhs) { - Fraction ret; - ret.n = n * rhs.d; - ret.d = d * rhs.n; - ret.reduce(); - return ret; - } + Fraction operator+(const Fraction &rhs) const { + Fraction ret; + ret.n = n * rhs.d + rhs.n * d; + ret.d = d * rhs.d; + ret.reduce(); + return ret; + } + Fraction operator-(const Fraction &rhs) const { + Fraction ret; + ret.n = n * rhs.d - rhs.n * d; + ret.d = d * rhs.d; + ret.reduce(); + return ret; + } + Fraction operator*(const Fraction &rhs) { + Fraction ret; + ret.n = n * rhs.n; + ret.d = d * rhs.d; + ret.reduce(); + return ret; + } + Fraction operator/(const Fraction &rhs) { + Fraction ret; + ret.n = n * rhs.d; + ret.d = d * rhs.n; + ret.reduce(); + return ret; + } }; \ No newline at end of file diff --git a/src/7-misc/kitamasa.cpp b/src/7-misc/kitamasa.cpp index bc52dcc..d01ddce 100644 --- a/src/7-misc/kitamasa.cpp +++ b/src/7-misc/kitamasa.cpp @@ -4,66 +4,66 @@ typedef vector poly; const int MOD = 1999; const int MAXN = 1010; int Mod(ll x) { - return (x %= MOD) < 0 ? x + MOD : x; + return (x %= MOD) < 0 ? x + MOD : x; } poly Mul(const poly &a, const poly &b) { - poly ret(sz(a) + sz(b) - 1); - for (int i = 0; i < sz(a); i++) - for (int j = 0; j < sz(b); j++) { - ret[i + j] = (ret[i + j] + a[i] * b[j]) % MOD; - } - return ret; + poly ret(sz(a) + sz(b) - 1); + for (int i = 0; i < sz(a); i++) + for (int j = 0; j < sz(b); j++) { + ret[i + j] = (ret[i + j] + a[i] * b[j]) % MOD; + } + return ret; } poly Div(const poly &a, const poly &b) { - poly ret(all(a)); - for (int i = sz(ret) - 1; i >= sz(b) - 1; i--) - for (int j = 0; j < sz(b); j++) { - ret[i + j - sz(b) + 1] = Mod(ret[i + j - sz(b) + 1] - ret[i] * b[j]); - } - ret.resize(sz(b) - 1); - return ret; + poly ret(all(a)); + for (int i = sz(ret) - 1; i >= sz(b) - 1; i--) + for (int j = 0; j < sz(b); j++) { + ret[i + j - sz(b) + 1] = Mod(ret[i + j - sz(b) + 1] - ret[i] * b[j]); + } + ret.resize(sz(b) - 1); + return ret; } // kitamasa: A_{n} = \sum c_{i}A_{n-i} = \sum d_{i}A_{i} // given A, c, n, get d, A_{n} in O(K^2 \log N) ll kitamasa(poly c, poly a, ll n) { - poly d = {1}; // result - poly xn = {0, 1}; // shift = x^1, x^2, x^4, ... - poly f(sz(c) + 1); // f(x) = x^K - \sum c_{i}x^{i} - f.back() = 1; - for (int i = 0; i < sz(c); i++) f[i] = Mod(-c[i]); - while (n) { - if (n & 1) d = Div(Mul(d, xn), f); - n >>= 1; - xn = Div(Mul(xn, xn), f); - } - ll ret = 0; - for (int i = 0; i < sz(a); i++) ret = Mod(ret + a[i] * d[i]); - return ret; + poly d = {1}; // result + poly xn = {0, 1}; // shift = x^1, x^2, x^4, ... + poly f(sz(c) + 1); // f(x) = x^K - \sum c_{i}x^{i} + f.back() = 1; + for (int i = 0; i < sz(c); i++) f[i] = Mod(-c[i]); + while (n) { + if (n & 1) d = Div(Mul(d, xn), f); + n >>= 1; + xn = Div(Mul(xn, xn), f); + } + ll ret = 0; + for (int i = 0; i < sz(a); i++) ret = Mod(ret + a[i] * d[i]); + return ret; } ll power(ll x, ll y) { - if (y == 0) return 1; - if (y == 1) return x; - ll res = power(x, y / 2); - return res * res % MOD * (y & 1 ? x : 1) % MOD; + if (y == 0) return 1; + if (y == 1) return x; + ll res = power(x, y / 2); + return res * res % MOD * (y & 1 ? x : 1) % MOD; } int n; ll m; vector dp; int main() { - cin >> n >> m; - if (m < n) { - cout << power(2, m - 1); - exit(0); - } - vector c(n); - for (int i = 0; i < n; i++) { - if (i == 0) c[i] = power(2, n - 1); - else c[i] = 1; - } - dp.resize(n); - dp[0] = 1; - for (int i = 1; i < n; i++) - for (int j = 0; j < i; j++) - dp[i] = (dp[i] + dp[j]) % MOD; - cout << kitamasa(c, dp, m); + cin >> n >> m; + if (m < n) { + cout << power(2, m - 1); + exit(0); + } + vector c(n); + for (int i = 0; i < n; i++) { + if (i == 0) c[i] = power(2, n - 1); + else c[i] = 1; + } + dp.resize(n); + dp[0] = 1; + for (int i = 1; i < n; i++) + for (int j = 0; j < i; j++) + dp[i] = (dp[i] + dp[j]) % MOD; + cout << kitamasa(c, dp, m); } \ No newline at end of file diff --git a/src/7-misc/lis_in_o_nlogn.cpp b/src/7-misc/lis_in_o_nlogn.cpp index f0e3410..02fe79d 100644 --- a/src/7-misc/lis_in_o_nlogn.cpp +++ b/src/7-misc/lis_in_o_nlogn.cpp @@ -7,14 +7,14 @@ int n; vector arr; int main() { - cin >> n; - for (int i = 1; i <= n; i++) { - int x; - cin >> x; - if (arr.empty() || arr.back() < x) arr.push_back(x); - else *lower_bound(arr.begin(), arr.end(), x) = x; - } - cout << arr.size(); + cin >> n; + for (int i = 1; i <= n; i++) { + int x; + cin >> x; + if (arr.empty() || arr.back() < x) arr.push_back(x); + else *lower_bound(arr.begin(), arr.end(), x) = x; + } + cout << arr.size(); } // 2. DP and Binary Search (Backtrace) @@ -26,33 +26,33 @@ vector arr; int idx[1010101]; int main() { - // input - cin >> n; - for (int i = 1; i <= n; i++) cin >> a[i]; - // solve - for (int i = 1; i <= n; i++) { - int x = a[i]; - if (arr.empty() || arr.back() < x) { - arr.push_back(x); - idx[i] = arr.size(); - } else { - int loc = lower_bound(arr.begin(), arr.end(), x) - arr.begin(); - arr[loc] = x, idx[i] = loc + 1; + // input + cin >> n; + for (int i = 1; i <= n; i++) cin >> a[i]; + // solve + for (int i = 1; i <= n; i++) { + int x = a[i]; + if (arr.empty() || arr.back() < x) { + arr.push_back(x); + idx[i] = arr.size(); + } else { + int loc = lower_bound(arr.begin(), arr.end(), x) - arr.begin(); + arr[loc] = x, idx[i] = loc + 1; + } } - } - // output - int ans1 = arr.size(); - cout << ans1 << '\n'; - vector ans2; - for (int i = n; i >= 1; i--) { - if (idx[i] == ans1) { - ans1--; - ans2.push_back(a[i]); + // output + int ans1 = arr.size(); + cout << ans1 << '\n'; + vector ans2; + for (int i = n; i >= 1; i--) { + if (idx[i] == ans1) { + ans1--; + ans2.push_back(a[i]); + } } - } - reverse(ans2.begin(), ans2.end()); - for (auto &i : ans2) - cout << i << ' '; + reverse(ans2.begin(), ans2.end()); + for (auto &i : ans2) + cout << i << ' '; } // 3. Segment Tree @@ -60,52 +60,52 @@ int main() { // OUTPUT: Print the length of the LIS. // TIME COMPLEXITY: O(NlogN). struct Seg { - int flag; // array size - vector t; - void build(int N) { - for (flag = 1; flag < N; flag <<= 1); - t.resize(2 * flag); - } - void modify(int p, int value) { // set value at position p - for (t[p += flag - 1] = value; p > 1; p >>= 1) t[p >> 1] = max(t[p], t[p ^ 1]); - } - int query(int l, int r) { - return query(l, r, 1, 1, flag); - } - int query(int l, int r, int n, int nl, int nr) { // sum on interval [l, r] - if (r < nl || nr < l) return 0; - if (l <= nl && nr <= r) return t[n]; + int flag; // array size + vector t; + void build(int N) { + for (flag = 1; flag < N; flag <<= 1); + t.resize(2 * flag); + } + void modify(int p, int value) { // set value at position p + for (t[p += flag - 1] = value; p > 1; p >>= 1) t[p >> 1] = max(t[p], t[p ^ 1]); + } + int query(int l, int r) { + return query(l, r, 1, 1, flag); + } + int query(int l, int r, int n, int nl, int nr) { // sum on interval [l, r] + if (r < nl || nr < l) return 0; + if (l <= nl && nr <= r) return t[n]; - int mid = (nl + nr) / 2; - return max(query(l, r, n << 1, nl, mid), query(l, r, n << 1 | 1, mid + 1, nr)); - } + int mid = (nl + nr) / 2; + return max(query(l, r, n << 1, nl, mid), query(l, r, n << 1 | 1, mid + 1, nr)); + } } seg; struct xidx { - int x, idx; + int x, idx; }; bool operator<(xidx &a, xidx &b) { - if (a.x != b.x) return a.x < b.x; - return a.idx > b.idx; + if (a.x != b.x) return a.x < b.x; + return a.idx > b.idx; } int n; vector a; void input() { - cin >> n; - for (int i = 0; i < n; i++) { - int x; - cin >> x; - a.push_back({x, i + 1}); - } + cin >> n; + for (int i = 0; i < n; i++) { + int x; + cin >> x; + a.push_back({x, i + 1}); + } } void f() { - seg.build(n); - sort(a.begin(), a.end()); - for (auto &i : a) { - seg.modify(i.idx, seg.query(1, i.idx - 1) + 1); - } + seg.build(n); + sort(a.begin(), a.end()); + for (auto &i : a) { + seg.modify(i.idx, seg.query(1, i.idx - 1) + 1); + } } int main() { - input(); - f(); - cout << seg.query(1, n); + input(); + f(); + cout << seg.query(1, n); } diff --git a/src/7-misc/simd.cpp b/src/7-misc/simd.cpp index 904194c..c61dba7 100644 --- a/src/7-misc/simd.cpp +++ b/src/7-misc/simd.cpp @@ -13,30 +13,30 @@ int N, M; int A[101010] __attribute__((aligned(32))); int main() { - cin >> N; - for (int i = 1; i <= N; i++) cin >> A[i]; - cin >> M; - while (M--) { - int op, x, y; - cin >> op >> x >> y; - if (op == 1) A[x] = y; - else { - int ans = 1e9 + 7; + cin >> N; + for (int i = 1; i <= N; i++) cin >> A[i]; + cin >> M; + while (M--) { + int op, x, y; + cin >> op >> x >> y; + if (op == 1) A[x] = y; + else { + int ans = 1e9 + 7; - int i; - __m256i mn = _mm256_set1_epi32(1e9 + 7); - for (i = x; i + 8 <= y; i += 8) { - __m256i cur = _mm256_load_si256((const __m256i *)&A[i]); - mn = _mm256_min_epi32(mn, cur); - } - for (; i <= y; i++) ans = min(ans, A[i]); + int i; + __m256i mn = _mm256_set1_epi32(1e9 + 7); + for (i = x; i + 8 <= y; i += 8) { + __m256i cur = _mm256_load_si256((const __m256i *)&A[i]); + mn = _mm256_min_epi32(mn, cur); + } + for (; i <= y; i++) ans = min(ans, A[i]); - int tmp[8]; - _mm256_store_si256((__m256i *)tmp, mn); - for (int i = 0; i < 8; i++) - ans = min(ans, tmp[i]); + int tmp[8]; + _mm256_store_si256((__m256i *)tmp, mn); + for (int i = 0; i < 8; i++) + ans = min(ans, tmp[i]); - cout << ans << '\n'; + cout << ans << '\n'; + } } - } } \ No newline at end of file diff --git a/src/7-misc/sqrt_decomposition_mos_algorithm.cpp b/src/7-misc/sqrt_decomposition_mos_algorithm.cpp index 0d25c48..f57b391 100644 --- a/src/7-misc/sqrt_decomposition_mos_algorithm.cpp +++ b/src/7-misc/sqrt_decomposition_mos_algorithm.cpp @@ -1,47 +1,47 @@ #include "../common/common.hpp" int sq; struct se { - int s, e, idx; - bool operator<(const se &rhs) const { - if (s / sq != rhs.s / sq) return s / sq < rhs.s / sq; - return e < rhs.e; - } - // Zigzag Mo's (faster than basic Mo's Algorithm) - // bool operator<(const se &rhs) const { - // if(s / sq != rhs.s / sq) return s / sq < rhs.s / sq; - // else return (s / sq) & 1 ? e < rhs.e : e > rhs.e; - // } + int s, e, idx; + bool operator<(const se &rhs) const { + if (s / sq != rhs.s / sq) return s / sq < rhs.s / sq; + return e < rhs.e; + } + // Zigzag Mo's (faster than basic Mo's Algorithm) + // bool operator<(const se &rhs) const { + // if(s / sq != rhs.s / sq) return s / sq < rhs.s / sq; + // else return (s / sq) & 1 ? e < rhs.e : e > rhs.e; + // } }; vector q; vector ans; void input() { - // TODO: 1. receive input 2. resize q, ans 3. calculate sq + // TODO: 1. receive input 2. resize q, ans 3. calculate sq } void add(int idx) { - // TODO: add value at idx from data structure + // TODO: add value at idx from data structure } void del(int idx) { - // TODO: remove value at idx from data structure + // TODO: remove value at idx from data structure } int query() { - // TODO: extract the current answer of the data structure + // TODO: extract the current answer of the data structure } void f() { - int s = q[0].s, e = q[0].e; - // TODO: initialize data structure - ans[q[0].idx] = query(); - for (int i = 1; i < q.size(); i++) { - while (q[i].s < s) add(--s); - while (e < q[i].e) add(++e); - while (s < q[i].s) del(s++); - while (q[i].e < e) del(e--); - ans[q[i].idx] = query(); - } + int s = q[0].s, e = q[0].e; + // TODO: initialize data structure + ans[q[0].idx] = query(); + for (int i = 1; i < q.size(); i++) { + while (q[i].s < s) add(--s); + while (e < q[i].e) add(++e); + while (s < q[i].s) del(s++); + while (q[i].e < e) del(e--); + ans[q[i].idx] = query(); + } } int main() { - input(); - sort(q.begin(), q.end()); - f(); - for (auto &i : ans) - cout << i << '\n'; + input(); + sort(q.begin(), q.end()); + f(); + for (auto &i : ans) + cout << i << '\n'; } \ No newline at end of file diff --git a/src/7-misc/system_of_difference_constraints.cpp b/src/7-misc/system_of_difference_constraints.cpp index 3b6eb13..bc64f7f 100644 --- a/src/7-misc/system_of_difference_constraints.cpp +++ b/src/7-misc/system_of_difference_constraints.cpp @@ -22,64 +22,64 @@ const ll INF = 1e18; int N, K; struct wv { - int w, v; + int w, v; }; vector adj[1010]; vector upper(1010, INF); void input() { - cin >> N >> K; - for (int i = 0; i < K; i++) { - int op, u, v, w; - cin >> op >> u >> v >> w; - if (op == 1) { - // x_u - x_v >= w - // iff x_v - x_u <= -w - adj[u].push_back({-w, v}); - } - if (op == 2) { - // x_u - x_v <= w - adj[v].push_back({w, u}); - } - if (op == 3) { - // x_u - x_v = w - // iff x_u - x_v <= w and x_v - x_u <= -w - adj[v].push_back({w, u}); - adj[u].push_back({-w, v}); + cin >> N >> K; + for (int i = 0; i < K; i++) { + int op, u, v, w; + cin >> op >> u >> v >> w; + if (op == 1) { + // x_u - x_v >= w + // iff x_v - x_u <= -w + adj[u].push_back({-w, v}); + } + if (op == 2) { + // x_u - x_v <= w + adj[v].push_back({w, u}); + } + if (op == 3) { + // x_u - x_v = w + // iff x_u - x_v <= w and x_v - x_u <= -w + adj[v].push_back({w, u}); + adj[u].push_back({-w, v}); + } } - } } int bellmanFord() { - upper[0] = 0; - int update = 1; - for (int i = 0; i < N + 2; i++) { - update = 0; - for (int now = 0; now <= N; now++) { - if (upper[now] == INF) continue; - for (wv e : adj[now]) { - int next = e.v; - if (upper[next] > upper[now] + e.w) { - upper[next] = upper[now] + e.w; - update = 1; + upper[0] = 0; + int update = 1; + for (int i = 0; i < N + 2; i++) { + update = 0; + for (int now = 0; now <= N; now++) { + if (upper[now] == INF) continue; + for (wv e : adj[now]) { + int next = e.v; + if (upper[next] > upper[now] + e.w) { + upper[next] = upper[now] + e.w; + update = 1; + } + } } - } + if (!update) break; } - if (!update) break; - } - return !update; + return !update; } int main() { - input(); - for (int i = 1; i <= N; i++) - adj[0].push_back({0, i}); - if (bellmanFord()) { - ll mn = INF, mx = -INF; - for (int i = 1; i <= N; i++) { - mn = min(mn, upper[i]); - mx = max(mx, upper[i]); - } - cout << (mx - mn <= 100 ? mx - mn : -1); - } else cout << -1; + input(); + for (int i = 1; i <= N; i++) + adj[0].push_back({0, i}); + if (bellmanFord()) { + ll mn = INF, mx = -INF; + for (int i = 1; i <= N; i++) { + mn = min(mn, upper[i]); + mx = max(mx, upper[i]); + } + cout << (mx - mn <= 100 ? mx - mn : -1); + } else cout << -1; } \ No newline at end of file diff --git a/src/7-misc/ternary_search.cpp b/src/7-misc/ternary_search.cpp index 63b209f..ce26e72 100644 --- a/src/7-misc/ternary_search.cpp +++ b/src/7-misc/ternary_search.cpp @@ -1,15 +1,15 @@ #include "../common/common.hpp" void ternarySearch() { - int l = 1, r = 10'000; - while (r - l >= 3) { - int mid1 = (2 * l + r) / 3; - int mid2 = (l + 2 * r) / 3; - int res1 = f(mid1), res2 = f(mid2); - if (res1 <= res2) l = mid1; - else r = mid2; - } - int res = 0; - for (int i = l; i <= r; i++) - res = max(res, f(i)); + int l = 1, r = 10'000; + while (r - l >= 3) { + int mid1 = (2 * l + r) / 3; + int mid2 = (l + 2 * r) / 3; + int res1 = f(mid1), res2 = f(mid2); + if (res1 <= res2) l = mid1; + else r = mid2; + } + int res = 0; + for (int i = l; i <= r; i++) + res = max(res, f(i)); } \ No newline at end of file