├── README.md ├── bignum_fft ├── bignum_fft.cc └── ntt.cc ├── bits ├── iterate_bitmasks_with_popcount.cc ├── iterate_submasks.cc ├── iterate_supermasks.cc ├── submask_sums.cc ├── subset_convolution.cc └── xor_basis.cc ├── bst ├── online_prefix_max.cc ├── orderset-pbds.cc ├── splay_lazy.cc └── splay_tree.cc ├── div_conquer └── count_pairs.cc ├── dp ├── distinct_subsequences.cc └── longest_common_subsequence.cc ├── euler_tour └── tree_sum_DS.cc ├── flow ├── assignment_problem_flow.cc ├── dinic.cc ├── dinic_matching.cc ├── max_weight_closure.cc ├── min_cost_flow.cc └── projects_and_tools.cc ├── geometry ├── dp_hull.cc ├── manhattan_mst.cc ├── monotonic_dp_hull_deque.cc ├── online_hull.cc └── point.cc ├── graph_theory ├── biconnected_components.cc ├── bridges.cc ├── check_bipartite.cc └── topological_sort.cc ├── hash ├── array_hash.cc └── string_hash.cc ├── heavy_light └── subtree_heavy_light.cc ├── io └── io.cc ├── miscellaneous ├── closest_left_right.cc ├── compress_array.cc ├── float_matrix.cc ├── floor_div_ceil_div.cc ├── highest_bit.cc ├── output_vector.cc └── radix_sort.cc ├── mod ├── barrett_int.cc ├── chinese_remainder_theorem.cc ├── choose.cc ├── mod_int.cc ├── mod_int_simple.cc └── mod_matrix.cc ├── number_theory ├── fraction.cc ├── miller_rabin.cc ├── sieve_factor.cc └── sieve_linear.cc ├── rmq_lca ├── block_rmq_mask.cc ├── cartesian_tree_parent_only.cc ├── monotonic_rmq_deque.cc ├── rmq_lca.cc └── weighted_lca.cc ├── scc_two_sat └── scc_two_sat.cc ├── seg_tree ├── basic_seg_tree.cc ├── fenwick_tree.cc ├── iterative_seg_tree.cc ├── persistent_array.cc ├── persistent_basic_seg_tree.cc ├── persistent_seg_tree.cc ├── seg_tree.cc └── seg_tree_beats.cc ├── shortest_path ├── bfs.cc ├── dijkstra.cc └── grid_bfs.cc ├── sqrt ├── mo.cc └── search_buckets.cc ├── strings ├── aho_corasick.cc ├── edit_distance.cc ├── kmp.cc ├── suffix_array.cc ├── trie.cc └── z_algorithm.cc ├── tree_centroid ├── basic_template.cc ├── subtract_subtrees_template.cc └── subtree_prefixes_template.cc ├── tree_dp ├── arrays_template_linear.cc ├── arrays_template_quadratic.cc ├── basic_template.cc └── up_down_tree_dp.cc └── union_find ├── bipartite_union_find.cc ├── kruskal.cc └── union_find_size.cc /README.md: -------------------------------------------------------------------------------- 1 | # competitive-programming 2 | Library code for programming contests 3 | -------------------------------------------------------------------------------- /bits/iterate_bitmasks_with_popcount.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | template 8 | void iterate_bitmasks_with_popcount(int n, int k, F &&f) { 9 | if (k == 0) { 10 | f(0); 11 | return; 12 | } 13 | 14 | int64_t mask = (1LL << k) - 1; 15 | 16 | while (mask < 1LL << n) { 17 | f(mask); 18 | int zeros = __builtin_ctzll(mask); 19 | int ones = __builtin_ctzll(~mask >> zeros); 20 | mask += (1LL << zeros) + (1LL << (ones - 1)) - 1; 21 | } 22 | } 23 | 24 | int main() { 25 | for (int n = 0; n <= 20; n++) { 26 | vector> masks_by_count(n + 1); 27 | 28 | for (int mask = 0; mask < 1 << n; mask++) 29 | masks_by_count[__builtin_popcount(mask)].push_back(mask); 30 | 31 | for (int k = 0; k <= n; k++) { 32 | vector k_masks; 33 | 34 | iterate_bitmasks_with_popcount(n, k, [&](int64_t mask) -> void { 35 | k_masks.push_back(int(mask)); 36 | }); 37 | 38 | assert(k_masks == masks_by_count[k]); 39 | } 40 | } 41 | 42 | const int maximum = 64; 43 | vector> choose(maximum + 1); 44 | 45 | for (int n = 0; n <= maximum; n++) { 46 | choose[n].resize(n + 1); 47 | choose[n][0] = choose[n][n] = 1; 48 | 49 | for (int r = 1; r < n; r++) 50 | choose[n][r] = choose[n - 1][r - 1] + choose[n - 1][r]; 51 | } 52 | 53 | auto test_masks = [&](int n, int k) -> void { 54 | int64_t previous = -1; 55 | uint64_t count = 0; 56 | 57 | iterate_bitmasks_with_popcount(n, k, [&](int64_t mask) -> void { 58 | assert(__builtin_popcountll(mask) == k); 59 | assert(mask > previous); 60 | previous = mask; 61 | count++; 62 | }); 63 | 64 | assert(count == choose[n][k]); 65 | }; 66 | 67 | test_masks(60, 5); 68 | test_masks(60, 55); 69 | } 70 | -------------------------------------------------------------------------------- /bits/iterate_submasks.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | void output(int mask, int n) { 9 | for (int i = 0; i < n; i++) 10 | cout << (mask >> i & 1); 11 | 12 | cout << '\n'; 13 | } 14 | 15 | int main() { 16 | int n, mask; 17 | cin >> n >> mask; 18 | 19 | for (int sub = mask; ; sub = (sub - 1) & mask) { 20 | printf("%3d: ", sub); 21 | output(sub, n); 22 | if (sub == 0) break; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /bits/iterate_supermasks.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | void output(int mask, int n) { 9 | for (int i = 0; i < n; i++) 10 | cout << (mask >> i & 1); 11 | 12 | cout << '\n'; 13 | } 14 | 15 | int main() { 16 | int n, mask; 17 | cin >> n >> mask; 18 | 19 | for (int super = mask; super < 1 << n; super = (super + 1) | mask) { 20 | printf("%3d: ", super); 21 | output(super, n); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bits/submask_sums.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // For every mask, computes the sum of `values[sub]` where `sub` is a submask of mask. 8 | template 9 | vector submask_sums(const vector &values) { 10 | int n = __builtin_ctz(int(values.size())); 11 | assert(int(values.size()) == 1 << n); 12 | vector dp(values.begin(), values.end()); 13 | 14 | // Broken profile DP where the intermediate DP state consists of the i-th suffix of the previous row and the i-th 15 | // prefix of the current row. 16 | for (int i = 0; i < n; i++) 17 | for (int base = 0; base < 1 << n; base += 1 << (i + 1)) 18 | for (int mask = base; mask < base + (1 << i); mask++) 19 | dp[mask + (1 << i)] += dp[mask]; 20 | 21 | return dp; 22 | } 23 | 24 | // For every mask, computes the sum of `values[sup]` where mask is a submask of `sup`. 25 | template 26 | vector supermask_sums(vector values) { 27 | reverse(values.begin(), values.end()); 28 | vector result = submask_sums(values); 29 | reverse(result.begin(), result.end()); 30 | return result; 31 | } 32 | 33 | // Does the inverse of `submask_sums`; returns the input that produces the given output. 34 | // Note that this also computes bitmask inclusion-exclusion. 35 | template 36 | vector mobius_transform(const vector &values) { 37 | int n = __builtin_ctz(int(values.size())); 38 | assert(int(values.size()) == 1 << n); 39 | vector dp(values.begin(), values.end()); 40 | 41 | for (int i = 0; i < n; i++) 42 | for (int base = 0; base < 1 << n; base += 1 << (i + 1)) 43 | for (int mask = base; mask < base + (1 << i); mask++) 44 | dp[mask + (1 << i)] -= dp[mask]; 45 | 46 | return dp; 47 | } 48 | 49 | // Does the inverse of `supermask_sums`; returns the input that produces the given output. 50 | template 51 | vector super_mobius_transform(vector values) { 52 | reverse(values.begin(), values.end()); 53 | vector result = mobius_transform(values); 54 | reverse(result.begin(), result.end()); 55 | return result; 56 | } 57 | 58 | int main() { 59 | ios::sync_with_stdio(false); 60 | #ifndef NEAL_DEBUG 61 | cin.tie(nullptr); 62 | #endif 63 | 64 | int N; 65 | cin >> N; 66 | vector A(1 << N); 67 | 68 | for (int &a : A) 69 | cin >> a; 70 | 71 | long double begin = clock(); 72 | vector sums = submask_sums(A); 73 | cerr << "submask_sums: " << (clock() - begin) / CLOCKS_PER_SEC << 's' << endl; 74 | 75 | for (int i = 0; i < 1 << N; i++) 76 | cout << sums[i] << (i < (1 << N) - 1 ? ' ' : '\n'); 77 | 78 | vector super_sums = supermask_sums(A); 79 | 80 | for (int i = 0; i < 1 << N; i++) 81 | cout << super_sums[i] << (i < (1 << N) - 1 ? ' ' : '\n'); 82 | 83 | vector A64 = mobius_transform(sums); 84 | assert(vector(A.begin(), A.end()) == A64); 85 | A64 = super_mobius_transform(super_sums); 86 | assert(vector(A.begin(), A.end()) == A64); 87 | } 88 | -------------------------------------------------------------------------------- /bits/subset_convolution.cc: -------------------------------------------------------------------------------- 1 | // See https://codeforces.com/blog/entry/72488 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | using namespace std; 18 | 19 | template ostream& operator<<(ostream &os, const pair &p) { return os << '(' << p.first << ", " << p.second << ')'; } 20 | template ostream& operator<<(ostream& os, const tuple& t) { os << '('; apply([&os](const Args&... args) { size_t n = 0; ((os << args << (++n != sizeof...(Args) ? ", " : "")), ...); }, t); return os << ')'; } 21 | template::value, typename T_container::value_type>::type> ostream& operator<<(ostream &os, const T_container &v) { os << '{'; string sep; for (const T &x : v) os << sep << x, sep = ", "; return os << '}'; } 22 | 23 | void dbg_out() { cerr << endl; } 24 | template void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); } 25 | 26 | #ifdef NEAL_DEBUG 27 | #define dbg(...) cerr << '[' << __FILE__ << ':' << __LINE__ << "] (" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__) 28 | #else 29 | #define dbg(...) 30 | #endif 31 | 32 | // For every mask, computes the sum of `values[sub]` where `sub` is a submask of mask. 33 | template 34 | vector submask_sums(const vector &values) { 35 | int n = __builtin_ctz(int(values.size())); 36 | assert(int(values.size()) == 1 << n); 37 | vector dp(values.begin(), values.end()); 38 | 39 | // Broken profile DP where the intermediate DP state consists of the i-th suffix of the previous row and the i-th 40 | // prefix of the current row. 41 | for (int i = 0; i < n; i++) 42 | for (int base = 0; base < 1 << n; base += 1 << (i + 1)) 43 | for (int mask = base; mask < base + (1 << i); mask++) 44 | dp[mask + (1 << i)] += dp[mask]; 45 | 46 | return dp; 47 | } 48 | 49 | // Does the inverse of `submask_sums`; returns the input that produces the given output. 50 | template 51 | vector mobius_transform(const vector &values) { 52 | int n = __builtin_ctz(int(values.size())); 53 | assert(int(values.size()) == 1 << n); 54 | vector dp(values.begin(), values.end()); 55 | 56 | for (int i = 0; i < n; i++) 57 | for (int base = 0; base < 1 << n; base += 1 << (i + 1)) 58 | for (int mask = base; mask < base + (1 << i); mask++) 59 | dp[mask + (1 << i)] -= dp[mask]; 60 | 61 | return dp; 62 | } 63 | 64 | template 65 | void iterate_bitmasks_with_popcount(int n, int k, F &&f) { 66 | if (k == 0) { 67 | f(0); 68 | return; 69 | } 70 | 71 | int mask = (1 << k) - 1; 72 | 73 | while (mask < 1 << n) { 74 | f(mask); 75 | int zeros = __builtin_ctz(mask); 76 | int ones = __builtin_ctz(~mask >> zeros); 77 | mask += (1 << zeros) + (1 << (ones - 1)) - 1; 78 | } 79 | } 80 | 81 | // Performs subset convolution, C[x | y] += A[x] * B[y] for all (x & y) = 0, in n^2 * 2^n time. 82 | template 83 | vector subset_convolution(const vector &A, const vector &B) { 84 | int n = __builtin_ctz(int(A.size())); 85 | assert(int(A.size()) == 1 << n && int(B.size()) == 1 << n); 86 | vector> FA(n + 1, vector(1 << n, 0)); 87 | vector> FB(n + 1, vector(1 << n, 0)); 88 | 89 | for (int mask = 0; mask < 1 << n; mask++) { 90 | FA[__builtin_popcount(mask)][mask] = A[mask]; 91 | FB[__builtin_popcount(mask)][mask] = B[mask]; 92 | } 93 | 94 | for (int c = 0; c < n; c++) { 95 | FA[c] = submask_sums(FA[c]); 96 | FB[c] = submask_sums(FB[c]); 97 | } 98 | 99 | vector C(1 << n, 0); 100 | 101 | for (int c = 0; c <= n; c++) { 102 | vector FC(1 << n, 0); 103 | 104 | // Add up all the ways to combine to c bits, with overlap. 105 | for (int i = 0; i <= c; i++) 106 | for (int mask = 0; mask < 1 << n; mask++) 107 | FC[mask] += FA[i][mask] * FB[c - i][mask]; 108 | 109 | // Subtract out combinations that actually have fewer than c bits. 110 | if (c > 1) 111 | FC = mobius_transform(FC); 112 | 113 | iterate_bitmasks_with_popcount(n, c, [&](int mask) -> void { 114 | C[mask] = FC[mask]; 115 | }); 116 | } 117 | 118 | return C; 119 | } 120 | 121 | // Performs reverse subset convolution, C[x] += A[x | y] * B[y] for all (x & y) = 0, in n^2 * 2^n time. 122 | template 123 | vector reverse_subset_convolution(vector A, const vector &B) { 124 | reverse(A.begin(), A.end()); 125 | vector result = subset_convolution(A, B); 126 | reverse(result.begin(), result.end()); 127 | return result; 128 | } 129 | 130 | 131 | template 132 | void output_vector(const T_vector &v, int start = 0, int end = -1) { 133 | if (end < 0) end = int(v.size()); 134 | 135 | for (int i = start; i < end; i++) 136 | if constexpr (add_one) 137 | cout << v[i] + 1 << (i < end - 1 ? ' ' : '\n'); 138 | else 139 | cout << v[i] << (i < end - 1 ? ' ' : '\n'); 140 | } 141 | 142 | int main() { 143 | ios::sync_with_stdio(false); 144 | #ifndef NEAL_DEBUG 145 | cin.tie(nullptr); 146 | #endif 147 | 148 | int N; 149 | cin >> N; 150 | vector A(1 << N), B(1 << N); 151 | 152 | for (auto &a : A) 153 | cin >> a; 154 | 155 | for (auto &b : B) 156 | cin >> b; 157 | 158 | output_vector(subset_convolution(A, B)); 159 | output_vector(reverse_subset_convolution(A, B)); 160 | } 161 | -------------------------------------------------------------------------------- /bits/xor_basis.cc: -------------------------------------------------------------------------------- 1 | 2 | const int BITS = 30; 3 | 4 | template 5 | struct xor_basis { 6 | // A list of basis values sorted in decreasing order, where each value has a unique highest bit. 7 | // We use a static array instead of a vector for better performance. 8 | T basis[BITS]; 9 | int n = 0; 10 | 11 | T min_value(T start) const { 12 | if (n == BITS) 13 | return 0; 14 | 15 | for (int i = 0; i < n; i++) 16 | start = min(start, start ^ basis[i]); 17 | 18 | return start; 19 | } 20 | 21 | T max_value(T start = 0) const { 22 | if (n == BITS) 23 | return (T(1) << BITS) - 1; 24 | 25 | for (int i = 0; i < n; i++) 26 | start = max(start, start ^ basis[i]); 27 | 28 | return start; 29 | } 30 | 31 | bool add(T x) { 32 | x = min_value(x); 33 | 34 | if (x == 0) 35 | return false; 36 | 37 | basis[n++] = x; 38 | int k = n - 1; 39 | 40 | // Insertion sort. 41 | while (k > 0 && basis[k] > basis[k - 1]) { 42 | swap(basis[k], basis[k - 1]); 43 | k--; 44 | } 45 | 46 | // Optional: remove the highest bit of x from other basis elements. 47 | // TODO: this can be removed for speed if desired. 48 | for (int i = k - 1; i >= 0; i--) 49 | basis[i] = min(basis[i], basis[i] ^ x); 50 | 51 | return true; 52 | } 53 | 54 | void merge(const xor_basis &other) { 55 | for (int i = 0; i < other.n && n < BITS; i++) 56 | add(other.basis[i]); 57 | } 58 | 59 | void merge(const xor_basis &a, const xor_basis &b) { 60 | if (a.n > b.n) { 61 | *this = a; 62 | merge(b); 63 | } else { 64 | *this = b; 65 | merge(a); 66 | } 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /bst/online_prefix_max.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | // Enables online insertion of (key, value) pairs and querying of maximum value out of keys less than a given limit. 11 | // To query minimums instead, set maximum_mode = false. 12 | template 13 | struct online_prefix_max { 14 | static bool is_better(T_value a, T_value b) { 15 | return maximum_mode ? b < a : a < b; 16 | } 17 | 18 | static T_value default_value() { 19 | return maximum_mode ? (is_signed::value ? -V_INF : 0) : V_INF; 20 | } 21 | 22 | map optimal; 23 | 24 | int size() const { 25 | return int(optimal.size()); 26 | } 27 | 28 | // Queries the maximum value in the map over all entries with key < `key_limit`. 29 | // TODO: when calling query, make sure to handle the empty case. 30 | T_value query(T_key key_limit) const { 31 | auto it = optimal.lower_bound(key_limit); 32 | return it == optimal.begin() ? default_value() : prev(it)->second; 33 | } 34 | 35 | // Adds an entry to the map and discards entries that are now obsolete. 36 | void insert(T_key key, T_value value) { 37 | auto it = optimal.upper_bound(key); 38 | 39 | // Quit if value is suboptimal. 40 | if (it != optimal.begin() && !is_better(value, prev(it)->second)) 41 | return; 42 | 43 | if (it != optimal.begin() && prev(it)->first == key) 44 | optimal.erase(prev(it)); 45 | 46 | while (it != optimal.end() && !is_better(it->second, value)) 47 | it = optimal.erase(it); 48 | 49 | optimal.insert(it, {key, value}); 50 | } 51 | }; 52 | 53 | 54 | template 55 | void merge_into(T_online_prefix_max &x, T_online_prefix_max &y) { 56 | if (x.size() < y.size()) 57 | swap(x, y); 58 | 59 | // Note: merge in linear time when x and y are close in size to improve worst-case runtime by a factor of log log n: 60 | // n log^2 n -> n log^2 n / log log n 61 | for (auto &p : y.optimal) 62 | x.insert(p.first, p.second); 63 | 64 | y.optimal.clear(); 65 | } 66 | 67 | 68 | const int64_t INF64 = int64_t(2e18) + 5; 69 | 70 | int main() { 71 | cerr << fixed << setprecision(4); 72 | 73 | int N; 74 | cin >> N; 75 | vector> inputs(N); 76 | 77 | for (auto &input : inputs) 78 | cin >> input.first >> input.second; 79 | 80 | vector outputs; 81 | outputs.reserve(N); 82 | 83 | long double begin = clock(); 84 | online_prefix_max prefix_max; 85 | int max_size = 0; 86 | 87 | for (auto &input : inputs) { 88 | int64_t key = input.first, value = input.second; 89 | outputs.push_back(prefix_max.query(key)); 90 | prefix_max.insert(key, value); 91 | max_size = max(max_size, prefix_max.size()); 92 | } 93 | 94 | cerr << "max size = " << max_size << endl; 95 | cerr << (clock() - begin) / CLOCKS_PER_SEC << 's' << endl; 96 | 97 | for (auto &output : outputs) 98 | cout << output << '\n'; 99 | } 100 | -------------------------------------------------------------------------------- /bst/orderset-pbds.cc: -------------------------------------------------------------------------------- 1 | // Solution to https://www.spoj.com/problems/ORDERSET/ 2 | #include 3 | using namespace std; 4 | 5 | #include 6 | using namespace __gnu_pbds; 7 | 8 | // WARNING: functions as a set (doesn't allow duplicates); insert pairs instead if duplicates are needed. 9 | // Consider using splay_tree instead if constant factor is an issue (e.g., log^2 solutions), especially with duplicates. 10 | template 11 | using ordered_set = tree, rb_tree_tag, tree_order_statistics_node_update>; 12 | 13 | int main() { 14 | int Q; 15 | scanf("%d", &Q); 16 | ordered_set values; 17 | 18 | for (int q = 0; q < Q; q++) { 19 | char op; 20 | int x; 21 | scanf(" %c %d", &op, &x); 22 | 23 | if (op == 'I') { 24 | values.insert(x); 25 | } else if (op == 'D') { 26 | values.erase(x); 27 | } else if (op == 'K') { 28 | x--; 29 | 30 | if (x >= int(values.size())) 31 | puts("invalid"); 32 | else 33 | // find_by_order(x) gives the x-th element in sorted order; if x = 2, gives the third smallest value. 34 | printf("%d\n", *values.find_by_order(x)); 35 | } else if (op == 'C') { 36 | // order_of_key(x) returns the count of elements < x. 37 | printf("%d\n", int(values.order_of_key(x))); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /div_conquer/count_pairs.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0200r0.html 10 | template class y_combinator_result { 11 | Fun fun_; 12 | public: 13 | template explicit y_combinator_result(T &&fun): fun_(std::forward(fun)) {} 14 | template decltype(auto) operator()(Args &&...args) { return fun_(std::ref(*this), std::forward(args)...); } 15 | }; 16 | template decltype(auto) y_combinator(Fun &&fun) { return y_combinator_result>(std::forward(fun)); } 17 | 18 | 19 | // Counts the number of pairs i < j such that compare(values[i], values[j]) is true. 20 | template 21 | int64_t count_pairs(T_array values, T_compare &&compare) { 22 | T_array buffer(values.size()); 23 | 24 | return y_combinator([&](auto self, int start, int end) -> int64_t { 25 | if (end - start <= 1) 26 | return 0; 27 | 28 | int mid = (start + end) / 2; 29 | int64_t answer = self(start, mid) + self(mid, end); 30 | int left = start, right = mid, n = 0; 31 | 32 | while (left < mid || right < end) 33 | if (left < mid && (right == end || compare(values[left], values[right]))) { 34 | buffer[n++] = values[left++]; 35 | } else { 36 | answer += left - start; 37 | buffer[n++] = values[right++]; 38 | } 39 | 40 | copy(buffer.begin(), buffer.begin() + n, values.begin() + start); 41 | return answer; 42 | })(0, int(values.size())); 43 | } 44 | 45 | 46 | int main() { 47 | ios::sync_with_stdio(false); 48 | #ifndef NEAL_DEBUG 49 | cin.tie(nullptr); 50 | #endif 51 | 52 | int n; 53 | cin >> n; 54 | vector values(n); 55 | 56 | for (auto &v : values) 57 | cin >> v; 58 | 59 | cout << count_pairs(values, less()) << '\n'; 60 | cout << count_pairs(values, greater()) << '\n'; 61 | cout << count_pairs(values, less_equal()) << '\n'; 62 | cout << count_pairs(values, greater_equal()) << '\n'; 63 | } 64 | -------------------------------------------------------------------------------- /dp/distinct_subsequences.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | template 10 | struct _m_int { 11 | int val; 12 | 13 | _m_int(int64_t v = 0) { 14 | if (v < 0) v = v % MOD + MOD; 15 | if (v >= MOD) v %= MOD; 16 | val = int(v); 17 | } 18 | 19 | _m_int(uint64_t v) { 20 | if (v >= MOD) v %= MOD; 21 | val = int(v); 22 | } 23 | 24 | _m_int(int v) : _m_int(int64_t(v)) {} 25 | _m_int(unsigned v) : _m_int(uint64_t(v)) {} 26 | 27 | explicit operator int() const { return val; } 28 | explicit operator unsigned() const { return val; } 29 | explicit operator int64_t() const { return val; } 30 | explicit operator uint64_t() const { return val; } 31 | explicit operator double() const { return val; } 32 | explicit operator long double() const { return val; } 33 | 34 | _m_int& operator+=(const _m_int &other) { 35 | val -= MOD - other.val; 36 | if (val < 0) val += MOD; 37 | return *this; 38 | } 39 | 40 | _m_int& operator-=(const _m_int &other) { 41 | val -= other.val; 42 | if (val < 0) val += MOD; 43 | return *this; 44 | } 45 | 46 | static unsigned fast_mod(uint64_t x, unsigned m = MOD) { 47 | #if !defined(_WIN32) || defined(_WIN64) 48 | return unsigned(x % m); 49 | #endif 50 | // Optimized mod for Codeforces 32-bit machines. 51 | // x must be less than 2^32 * m for this to work, so that x / m fits in an unsigned 32-bit int. 52 | unsigned x_high = unsigned(x >> 32), x_low = unsigned(x); 53 | unsigned quot, rem; 54 | asm("divl %4\n" 55 | : "=a" (quot), "=d" (rem) 56 | : "d" (x_high), "a" (x_low), "r" (m)); 57 | return rem; 58 | } 59 | 60 | _m_int& operator*=(const _m_int &other) { 61 | val = fast_mod(uint64_t(val) * other.val); 62 | return *this; 63 | } 64 | 65 | _m_int& operator/=(const _m_int &other) { 66 | return *this *= other.inv(); 67 | } 68 | 69 | friend _m_int operator+(const _m_int &a, const _m_int &b) { return _m_int(a) += b; } 70 | friend _m_int operator-(const _m_int &a, const _m_int &b) { return _m_int(a) -= b; } 71 | friend _m_int operator*(const _m_int &a, const _m_int &b) { return _m_int(a) *= b; } 72 | friend _m_int operator/(const _m_int &a, const _m_int &b) { return _m_int(a) /= b; } 73 | 74 | _m_int& operator++() { 75 | val = val == MOD - 1 ? 0 : val + 1; 76 | return *this; 77 | } 78 | 79 | _m_int& operator--() { 80 | val = val == 0 ? MOD - 1 : val - 1; 81 | return *this; 82 | } 83 | 84 | _m_int operator++(int) { _m_int before = *this; ++*this; return before; } 85 | _m_int operator--(int) { _m_int before = *this; --*this; return before; } 86 | 87 | _m_int operator-() const { 88 | return val == 0 ? 0 : MOD - val; 89 | } 90 | 91 | friend bool operator==(const _m_int &a, const _m_int &b) { return a.val == b.val; } 92 | friend bool operator!=(const _m_int &a, const _m_int &b) { return a.val != b.val; } 93 | friend bool operator<(const _m_int &a, const _m_int &b) { return a.val < b.val; } 94 | friend bool operator>(const _m_int &a, const _m_int &b) { return a.val > b.val; } 95 | friend bool operator<=(const _m_int &a, const _m_int &b) { return a.val <= b.val; } 96 | friend bool operator>=(const _m_int &a, const _m_int &b) { return a.val >= b.val; } 97 | 98 | static const int SAVE_INV = int(1e6) + 5; 99 | static _m_int save_inv[SAVE_INV]; 100 | 101 | static void prepare_inv() { 102 | // Ensures that MOD is prime, which is necessary for the inverse algorithm below. 103 | for (int64_t p = 2; p * p <= MOD; p += p % 2 + 1) 104 | assert(MOD % p != 0); 105 | 106 | save_inv[0] = 0; 107 | save_inv[1] = 1; 108 | 109 | for (int i = 2; i < SAVE_INV; i++) 110 | save_inv[i] = save_inv[MOD % i] * (MOD - MOD / i); 111 | } 112 | 113 | _m_int inv() const { 114 | if (save_inv[1] == 0) 115 | prepare_inv(); 116 | 117 | if (val < SAVE_INV) 118 | return save_inv[val]; 119 | 120 | _m_int product = 1; 121 | int v = val; 122 | 123 | do { 124 | product *= MOD - MOD / v; 125 | v = MOD % v; 126 | } while (v >= SAVE_INV); 127 | 128 | return product * save_inv[v]; 129 | } 130 | 131 | _m_int pow(int64_t p) const { 132 | if (p < 0) 133 | return inv().pow(-p); 134 | 135 | _m_int a = *this, result = 1; 136 | 137 | while (p > 0) { 138 | if (p & 1) 139 | result *= a; 140 | 141 | p >>= 1; 142 | 143 | if (p > 0) 144 | a *= a; 145 | } 146 | 147 | return result; 148 | } 149 | 150 | friend ostream& operator<<(ostream &os, const _m_int &m) { 151 | return os << m.val; 152 | } 153 | }; 154 | 155 | template _m_int _m_int::save_inv[_m_int::SAVE_INV]; 156 | 157 | const int MOD = 998244353; 158 | using mod_int = _m_int; 159 | 160 | // Counts the number of distinct nonempty subsequences in an array. 161 | template 162 | mod_int distinct_subsequences(const vector &A) { 163 | int n = int(A.size()); 164 | vector dp(n + 1, 0); 165 | dp[0] = 1; 166 | map last; 167 | // TODO: replace `last` with a hash map or a vector if applicable. 168 | 169 | for (int i = 0; i < n; i++) { 170 | dp[i + 1] = 2 * dp[i]; 171 | 172 | if (last.find(A[i]) != last.end()) 173 | dp[i + 1] -= dp[last[A[i]]]; 174 | 175 | last[A[i]] = i; 176 | } 177 | 178 | // Remove the empty subsequence. 179 | return dp[n] - 1; 180 | } 181 | 182 | 183 | int main() { 184 | ios::sync_with_stdio(false); 185 | #ifndef NEAL_DEBUG 186 | cin.tie(nullptr); 187 | #endif 188 | 189 | int N; 190 | cin >> N; 191 | vector A(N); 192 | 193 | for (auto &a : A) 194 | cin >> a; 195 | 196 | cout << distinct_subsequences(A) << '\n'; 197 | } 198 | -------------------------------------------------------------------------------- /dp/longest_common_subsequence.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | bool is_subsequence(const string &sub, const string &str) { 11 | size_t index = 0; 12 | 13 | for (char ch : str) 14 | if (index < sub.size() && ch == sub[index]) 15 | index++; 16 | 17 | return index == sub.size(); 18 | } 19 | 20 | int longest_common_subsequence_quadratic_memory(const string &S, const string &T) { 21 | int n = int(S.size()); 22 | int m = int(T.size()); 23 | vector> dp(n + 1, vector(m + 1, 0)); 24 | 25 | for (int i = 0; i < n; i++) 26 | for (int j = 0; j < m; j++) 27 | dp[i + 1][j + 1] = max({dp[i + 1][j], dp[i][j + 1], dp[i][j] + (S[i] == T[j])}); 28 | 29 | return dp[n][m]; 30 | } 31 | 32 | int longest_common_subsequence(const string &S, const string &T) { 33 | int n = int(S.size()); 34 | int m = int(T.size()); 35 | vector dp(m + 1, 0); 36 | 37 | for (int i = 0; i < n; i++) { 38 | vector next_dp(m + 1, 0); 39 | 40 | for (int j = 0; j < m; j++) 41 | next_dp[j + 1] = max({next_dp[j], dp[j + 1], dp[j] + (S[i] == T[j])}); 42 | 43 | dp.swap(next_dp); 44 | } 45 | 46 | return dp[m]; 47 | } 48 | 49 | string construct_longest_common_subsequence_bitset(const string &S, const string &T) { 50 | int n = int(S.size()); 51 | int m = int(T.size()); 52 | vector dp(m + 1, 0); 53 | vector> previous(n + 1, vector(m + 1, false)); 54 | 55 | for (int i = 0; i < n; i++) { 56 | vector next_dp(m + 1, 0); 57 | 58 | for (int j = 0; j < m; j++) { 59 | next_dp[j + 1] = max({next_dp[j], dp[j + 1], dp[j] + (S[i] == T[j])}); 60 | previous[i + 1][j + 1] = next_dp[j + 1] == next_dp[j]; 61 | } 62 | 63 | dp.swap(next_dp); 64 | } 65 | 66 | int a = n, b = m; 67 | string common; 68 | 69 | while (a > 0 && b > 0) { 70 | if (S[a - 1] == T[b - 1]) { 71 | common += S[a - 1]; 72 | a--; b--; 73 | continue; 74 | } 75 | 76 | if (previous[a][b]) 77 | b--; 78 | else 79 | a--; 80 | } 81 | 82 | reverse(common.begin(), common.end()); 83 | return common; 84 | } 85 | 86 | string construct_longest_common_subsequence_hirschberg(const string_view &S, const string_view &T) { 87 | int n = int(S.size()); 88 | int m = int(T.size()); 89 | 90 | if (n == 0 || m == 0) 91 | return ""; 92 | 93 | if (n == 1) 94 | return T.find(S[0]) == string::npos ? "" : string(1, S[0]); 95 | 96 | int mid = n / 2; 97 | vector dp_first(m + 1, 0), dp_second(m + 1, 0); 98 | vector next_dp(m + 1, 0); 99 | 100 | for (int i = 0; i < mid; i++) { 101 | for (int j = 0; j < m; j++) 102 | next_dp[j + 1] = max({next_dp[j], dp_first[j + 1], dp_first[j] + (S[i] == T[j])}); 103 | 104 | dp_first.swap(next_dp); 105 | } 106 | 107 | next_dp.assign(m + 1, 0); 108 | 109 | for (int i = n - 1; i >= mid; i--) { 110 | for (int j = m - 1; j >= 0; j--) 111 | next_dp[j] = max({next_dp[j + 1], dp_second[j], dp_second[j + 1] + (S[i] == T[j])}); 112 | 113 | dp_second.swap(next_dp); 114 | } 115 | 116 | int split = 0; 117 | 118 | for (int j = 1; j <= m; j++) 119 | if (dp_first[j] + dp_second[j] > dp_first[split] + dp_second[split]) 120 | split = j; 121 | 122 | dp_first.clear(); 123 | dp_second.clear(); 124 | next_dp.clear(); 125 | 126 | return ( 127 | construct_longest_common_subsequence_hirschberg(S.substr(0, mid), T.substr(0, split)) + 128 | construct_longest_common_subsequence_hirschberg(S.substr(mid), T.substr(split)) 129 | ); 130 | } 131 | 132 | int main() { 133 | ios::sync_with_stdio(false); 134 | #ifndef NEAL_DEBUG 135 | cin.tie(nullptr); 136 | #endif 137 | 138 | cerr << setprecision(3); 139 | 140 | string S, T; 141 | cin >> S >> T; 142 | long double begin; 143 | 144 | begin = clock(); 145 | int longest = longest_common_subsequence(S, T); 146 | cerr << "standard : " << (clock() - begin) / CLOCKS_PER_SEC << 's' << endl; 147 | 148 | begin = clock(); 149 | string answer = construct_longest_common_subsequence_bitset(S, T); 150 | cerr << "bitset : " << (clock() - begin) / CLOCKS_PER_SEC << 's' << endl; 151 | 152 | begin = clock(); 153 | assert(longest_common_subsequence_quadratic_memory(S, T) == longest); 154 | cerr << "quadratic : " << (clock() - begin) / CLOCKS_PER_SEC << 's' << endl; 155 | 156 | assert(int(answer.size()) == longest); 157 | assert(is_subsequence(answer, S) && is_subsequence(answer, T)); 158 | 159 | begin = clock(); 160 | string hirschberg_answer = construct_longest_common_subsequence_hirschberg(S, T); 161 | cerr << "hirschberg: " << (clock() - begin) / CLOCKS_PER_SEC << 's' << endl; 162 | 163 | assert(int(hirschberg_answer.size()) == longest); 164 | assert(is_subsequence(hirschberg_answer, S) && is_subsequence(hirschberg_answer, T)); 165 | 166 | cout << longest << '\n'; 167 | cout << answer << '\n'; 168 | } 169 | -------------------------------------------------------------------------------- /flow/dinic.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | const int INF = int(1e9) + 5; 11 | 12 | enum edge_type : uint8_t { DIRECTIONAL, DIRECTIONAL_REVERSE, BIDIRECTIONAL }; 13 | 14 | // Warning: flow_t must be able to handle the sum of flows, not just individual edges. 15 | template 16 | struct dinic { 17 | struct edge { 18 | int node, rev; 19 | flow_t capacity; 20 | edge_type type; 21 | 22 | edge() {} 23 | 24 | edge(int _node, int _rev, flow_t _capacity, edge_type _type) 25 | : node(_node), rev(_rev), capacity(_capacity), type(_type) {} 26 | }; 27 | 28 | int V = -1; 29 | vector> adj; 30 | vector dist; 31 | vector edge_index; 32 | bool flow_called = false; 33 | 34 | dinic(int vertices = -1) { 35 | if (vertices >= 0) 36 | init(vertices); 37 | } 38 | 39 | void init(int vertices) { 40 | V = vertices; 41 | adj.assign(V, {}); 42 | flow_called = false; 43 | } 44 | 45 | void _add_edge(int u, int v, flow_t capacity1, flow_t capacity2, edge_type type1, edge_type type2) { 46 | assert(0 <= min(u, v) && max(u, v) < V); 47 | assert(capacity1 >= 0 && capacity2 >= 0); 48 | edge uv_edge(v, int(adj[v].size()) + (u == v ? 1 : 0), capacity1, type1); 49 | edge vu_edge(u, int(adj[u].size()), capacity2, type2); 50 | adj[u].push_back(uv_edge); 51 | adj[v].push_back(vu_edge); 52 | } 53 | 54 | void add_directional_edge(int u, int v, flow_t capacity) { 55 | _add_edge(u, v, capacity, 0, DIRECTIONAL, DIRECTIONAL_REVERSE); 56 | } 57 | 58 | void add_bidirectional_edge(int u, int v, flow_t capacity) { 59 | _add_edge(u, v, capacity, capacity, BIDIRECTIONAL, BIDIRECTIONAL); 60 | } 61 | 62 | edge &reverse_edge(const edge &e) { 63 | return adj[e.node][e.rev]; 64 | } 65 | 66 | bool bfs(int source, int sink) { 67 | vector q(V); 68 | int q_start = 0, q_end = 0; 69 | dist.assign(V, INF); 70 | 71 | auto bfs_check = [&](int node, int new_dist) -> void { 72 | if (new_dist < dist[node]) { 73 | dist[node] = new_dist; 74 | q[q_end++] = node; 75 | } 76 | }; 77 | 78 | bfs_check(source, 0); 79 | 80 | while (q_start < q_end) { 81 | int top = q[q_start++]; 82 | 83 | for (edge &e : adj[top]) 84 | if (e.capacity > 0) 85 | bfs_check(e.node, dist[top] + 1); 86 | } 87 | 88 | return dist[sink] < INF; 89 | } 90 | 91 | flow_t dfs(int node, flow_t path_cap, int sink) { 92 | if (node == sink) 93 | return path_cap; 94 | 95 | if (dist[node] >= dist[sink]) 96 | return 0; 97 | 98 | flow_t total_flow = 0; 99 | 100 | // Because we are only performing DFS in increasing order of dist, we don't have to revisit fully searched edges 101 | // again later. 102 | while (edge_index[node] < int(adj[node].size())) { 103 | edge &e = adj[node][edge_index[node]]; 104 | 105 | if (e.capacity > 0 && dist[node] + 1 == dist[e.node]) { 106 | flow_t path = dfs(e.node, min(path_cap, e.capacity), sink); 107 | path_cap -= path; 108 | e.capacity -= path; 109 | reverse_edge(e).capacity += path; 110 | total_flow += path; 111 | } 112 | 113 | // If path_cap is 0, we don't want to increment edge_index[node] as this edge may not be fully searched yet. 114 | if (path_cap == 0) 115 | break; 116 | 117 | edge_index[node]++; 118 | } 119 | 120 | return total_flow; 121 | } 122 | 123 | // Can also be used to reverse flow or compute incremental flows after graph modification. 124 | flow_t flow(int source, int sink, flow_t flow_cap = numeric_limits::max()) { 125 | assert(V >= 0); 126 | flow_called = true; 127 | flow_t total_flow = 0; 128 | 129 | while (flow_cap > 0 && bfs(source, sink)) { 130 | edge_index.assign(V, 0); 131 | flow_t increment = dfs(source, flow_cap, sink); 132 | assert(increment > 0); 133 | total_flow += increment; 134 | flow_cap -= increment; 135 | } 136 | 137 | return total_flow; 138 | } 139 | 140 | vector reachable; 141 | 142 | void _reachable_dfs(int node) { 143 | reachable[node] = true; 144 | 145 | for (edge &e : adj[node]) 146 | if (e.capacity > 0 && !reachable[e.node]) 147 | _reachable_dfs(e.node); 148 | } 149 | 150 | void solve_reachable(int source) { 151 | reachable.assign(V, false); 152 | _reachable_dfs(source); 153 | } 154 | 155 | // Returns a list of {capacity, {from_node, to_node}} representing edges in the min cut. 156 | vector>> min_cut(int source) { 157 | assert(flow_called); 158 | solve_reachable(source); 159 | vector>> cut; 160 | 161 | for (int node = 0; node < V; node++) 162 | for (edge &e : adj[node]) 163 | if (reachable[node] && !reachable[e.node] && e.type != DIRECTIONAL_REVERSE) { 164 | flow_t rev_cap = reverse_edge(e).capacity; 165 | flow_t original_cap = e.type == BIDIRECTIONAL ? rev_cap / 2 : rev_cap; 166 | cut.emplace_back(original_cap, make_pair(node, e.node)); 167 | } 168 | 169 | return cut; 170 | } 171 | 172 | // Helper function for setting up incremental / reverse flows. Can become invalid if adding additional edges. 173 | edge *find_edge(int a, int b) { 174 | for (edge &e : adj[a]) 175 | if (e.node == b) 176 | return &e; 177 | 178 | return nullptr; 179 | } 180 | }; 181 | 182 | 183 | // Accepted on https://www.spoj.com/problems/FASTFLOW/ 184 | 185 | int main() { 186 | ios::sync_with_stdio(false); 187 | #ifndef NEAL_DEBUG 188 | cin.tie(nullptr); 189 | #endif 190 | 191 | int N, M; 192 | string str; 193 | cin >> str; 194 | bool directed_mode = false; 195 | 196 | if (str == "directed") { 197 | directed_mode = true; 198 | cin >> N >> M; 199 | } else { 200 | N = stoi(str); 201 | cin >> M; 202 | } 203 | 204 | dinic graph(N); 205 | 206 | for (int i = 0; i < M; i++) { 207 | int a, b, c; 208 | cin >> a >> b >> c; 209 | a--; b--; 210 | 211 | if (directed_mode) 212 | graph.add_directional_edge(a, b, c); 213 | else 214 | graph.add_bidirectional_edge(a, b, c); 215 | } 216 | 217 | int64_t answer = graph.flow(0, N - 1); 218 | cout << answer << '\n'; 219 | 220 | auto cut = graph.min_cut(0); 221 | int64_t cut_sum = 0; 222 | 223 | for (auto &t : cut) 224 | cut_sum += t.first; 225 | 226 | assert(answer == cut_sum); 227 | } 228 | -------------------------------------------------------------------------------- /flow/dinic_matching.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | const int INF = int(1e9) + 5; 10 | 11 | struct dinic_matching { 12 | int n, m; 13 | vector> adj; 14 | vector dist; 15 | vector right_match, left_match; 16 | vector edge_index; 17 | bool match_called = false; 18 | int matches = 0; 19 | 20 | dinic_matching() { 21 | init(0, 0); 22 | } 23 | 24 | dinic_matching(int _n, int _m) { 25 | init(_n, _m); 26 | } 27 | 28 | void init(int _n, int _m) { 29 | n = _n; 30 | m = _m; 31 | adj.assign(n, {}); 32 | match_called = false; 33 | matches = 0; 34 | } 35 | 36 | void add_edge(int a, int b) { 37 | assert(0 <= a && a < n); 38 | assert(0 <= b && b < m); 39 | adj[a].push_back(b); 40 | } 41 | 42 | bool bfs() { 43 | vector q(n); 44 | int q_start = 0, q_end = 0; 45 | dist.assign(n, INF); 46 | 47 | auto bfs_check = [&](int node, int new_dist) -> void { 48 | if (new_dist < dist[node]) { 49 | dist[node] = new_dist; 50 | q[q_end++] = node; 51 | } 52 | }; 53 | 54 | for (int i = 0; i < n; i++) 55 | if (right_match[i] < 0) 56 | bfs_check(i, 0); 57 | 58 | bool has_path = false; 59 | 60 | while (q_start < q_end) { 61 | int left = q[q_start++]; 62 | 63 | for (int right : adj[left]) 64 | if (left_match[right] < 0) 65 | has_path = true; 66 | else 67 | bfs_check(left_match[right], dist[left] + 1); 68 | } 69 | 70 | return has_path; 71 | } 72 | 73 | bool dfs(int left) { 74 | // Because we are only performing DFS in increasing order of dist, we don't have to revisit fully searched edges 75 | // again later. 76 | while (edge_index[left] < int(adj[left].size())) { 77 | int right = adj[left][edge_index[left]++]; 78 | bool solved = false; 79 | 80 | if (left_match[right] < 0 || (dist[left] + 1 == dist[left_match[right]] && dfs(left_match[right]))) { 81 | left_match[right] = left; 82 | right_match[left] = right; 83 | solved = true; 84 | } 85 | 86 | if (solved) 87 | return true; 88 | } 89 | 90 | dist[left] = INF; 91 | return false; 92 | } 93 | 94 | int match() { 95 | match_called = true; 96 | right_match.assign(n, -1); 97 | left_match.assign(m, -1); 98 | matches = 0; 99 | 100 | while (bfs()) { 101 | edge_index.assign(n, 0); 102 | 103 | for (int i = 0; i < n; i++) 104 | if (right_match[i] < 0 && dfs(i)) 105 | matches++; 106 | } 107 | 108 | return matches; 109 | } 110 | 111 | vector reachable_left, reachable_right; 112 | 113 | void _reachable_dfs(int left) { 114 | reachable_left[left] = true; 115 | 116 | for (int right : adj[left]) 117 | if (right != right_match[left] && !reachable_right[right]) { 118 | reachable_right[right] = true; 119 | int next_left = left_match[right]; 120 | 121 | if (next_left >= 0 && !reachable_left[next_left]) 122 | _reachable_dfs(next_left); 123 | } 124 | } 125 | 126 | void solve_reachable() { 127 | reachable_left.assign(n, false); 128 | reachable_right.assign(m, false); 129 | 130 | for (int i = 0; i < n; i++) 131 | if (right_match[i] < 0 && !reachable_left[i]) 132 | _reachable_dfs(i); 133 | } 134 | 135 | // The min vertex cover in a bipartite graph corresponds to the min cut in its flow graph. 136 | vector min_vertex_cover() { 137 | assert(match_called); 138 | solve_reachable(); 139 | vector cover; 140 | 141 | for (int i = 0; i < n; i++) 142 | if (!reachable_left[i]) 143 | cover.push_back(i); 144 | 145 | for (int i = 0; i < m; i++) 146 | if (reachable_right[i]) 147 | cover.push_back(n + i); 148 | 149 | assert(int(cover.size()) == matches); 150 | return cover; 151 | } 152 | 153 | // The max independent set is the complement of the min vertex cover. 154 | vector max_independent_set() { 155 | assert(match_called); 156 | solve_reachable(); 157 | vector independent_set; 158 | 159 | for (int i = 0; i < n; i++) 160 | if (reachable_left[i]) 161 | independent_set.push_back(i); 162 | 163 | for (int i = 0; i < m; i++) 164 | if (!reachable_right[i]) 165 | independent_set.push_back(n + i); 166 | 167 | assert(int(independent_set.size()) + matches == n + m); 168 | return independent_set; 169 | } 170 | }; 171 | 172 | 173 | // Accepted on https://www.spoj.com/problems/MATCHING/ 174 | 175 | int main() { 176 | int N, M, P; 177 | scanf("%d %d %d", &N, &M, &P); 178 | dinic_matching graph(N, M); 179 | 180 | for (int i = 0; i < P; i++) { 181 | int a, b; 182 | scanf("%d %d", &a, &b); 183 | a--; b--; 184 | graph.add_edge(a, b); 185 | } 186 | 187 | printf("%d\n", graph.match()); 188 | } 189 | -------------------------------------------------------------------------------- /flow/min_cost_flow.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | // Warning: flow_t and cost_t must be able to handle the sums of flows and costs, not just individual edges. 11 | template 12 | struct min_cost_flow { 13 | const cost_t COST_INF = numeric_limits::max() / 2; 14 | 15 | struct edge { 16 | int node, rev; 17 | flow_t capacity; 18 | cost_t cost; 19 | 20 | edge() {} 21 | 22 | edge(int _node, int _rev, flow_t _capacity, cost_t _cost) 23 | : node(_node), rev(_rev), capacity(_capacity), cost(_cost) {} 24 | }; 25 | 26 | int V = -1, E = 0; 27 | vector> adj; 28 | vector dist; 29 | vector prv; 30 | vector prev_edge; 31 | bool too_much_bellman_ford = false; 32 | 33 | min_cost_flow(int vertices = -1) { 34 | if (vertices >= 0) 35 | init(vertices); 36 | } 37 | 38 | void init(int vertices) { 39 | V = vertices; 40 | E = 0; 41 | adj.assign(V, {}); 42 | dist.resize(V); 43 | prv.resize(V); 44 | prev_edge.resize(V); 45 | too_much_bellman_ford = false; 46 | } 47 | 48 | void add_directional_edge(int u, int v, flow_t capacity, cost_t cost) { 49 | assert(0 <= min(u, v) && max(u, v) < V); 50 | assert(capacity >= 0); 51 | edge uv_edge(v, int(adj[v].size()) + (u == v ? 1 : 0), capacity, cost); 52 | edge vu_edge(u, int(adj[u].size()), 0, -cost); 53 | adj[u].push_back(uv_edge); 54 | adj[v].push_back(vu_edge); 55 | E++; 56 | } 57 | 58 | edge &reverse_edge(const edge &e) { 59 | return adj[e.node][e.rev]; 60 | } 61 | 62 | bool bellman_ford(int source, int sink) { 63 | dist.assign(V, COST_INF); 64 | prv.assign(V, -1); 65 | prev_edge.assign(V, nullptr); 66 | 67 | int64_t work = 0; 68 | vector last_seen(V, -1); 69 | vector nodes = {source}, next_nodes; 70 | dist[source] = 0; 71 | 72 | for (int iteration = 0; iteration < V; iteration++) { 73 | next_nodes.clear(); 74 | 75 | for (int node : nodes) { 76 | for (edge &e : adj[node]) 77 | if (e.capacity > 0 && dist[node] + e.cost < dist[e.node]) { 78 | dist[e.node] = dist[node] + e.cost; 79 | prv[e.node] = node; 80 | prev_edge[e.node] = &e; 81 | 82 | if (last_seen[e.node] != iteration) { 83 | last_seen[e.node] = iteration; 84 | next_nodes.push_back(e.node); 85 | } 86 | } 87 | 88 | work += adj[node].size(); 89 | } 90 | 91 | swap(nodes, next_nodes); 92 | } 93 | 94 | if (work > 1.75L * E * (V == 0 ? 0 : 32 - __builtin_clz(V)) + 100) { 95 | too_much_bellman_ford = true; 96 | return false; 97 | } 98 | 99 | return prv[sink] != -1; 100 | } 101 | 102 | struct dijkstra_state { 103 | cost_t dist; 104 | int node; 105 | 106 | dijkstra_state() {} 107 | 108 | dijkstra_state(cost_t _dist, int _node) : dist(_dist), node(_node) {} 109 | 110 | bool operator<(const dijkstra_state &other) const { 111 | return dist > other.dist; 112 | } 113 | }; 114 | 115 | void dijkstra_check(priority_queue &pq, int node, cost_t new_dist, int previous, edge *previous_edge) { 116 | if (new_dist < dist[node]) { 117 | dist[node] = new_dist; 118 | prv[node] = previous; 119 | prev_edge[node] = previous_edge; 120 | pq.emplace(dist[node], node); 121 | } 122 | } 123 | 124 | bool dijkstra(int source, int sink) { 125 | dist.assign(V, COST_INF); 126 | prv.assign(V, -1); 127 | prev_edge.assign(V, nullptr); 128 | 129 | priority_queue pq; 130 | dijkstra_check(pq, source, 0, -1, nullptr); 131 | 132 | while (!pq.empty()) { 133 | dijkstra_state top = pq.top(); 134 | pq.pop(); 135 | 136 | if (top.dist > dist[top.node]) 137 | continue; 138 | 139 | for (edge &e : adj[top.node]) 140 | if (e.capacity > 0) 141 | dijkstra_check(pq, e.node, top.dist + e.cost, top.node, &e); 142 | } 143 | 144 | return prv[sink] != -1; 145 | } 146 | 147 | void reduce_cost() { 148 | for (int i = 0; i < V; i++) 149 | for (edge &e : adj[i]) 150 | if (dist[i] < COST_INF && dist[e.node] < COST_INF) 151 | e.cost += dist[i] - dist[e.node]; 152 | } 153 | 154 | pair solve_min_cost_flow(int source, int sink, flow_t flow_goal = numeric_limits::max()) { 155 | assert(V >= 0); 156 | flow_t total_flow = 0; 157 | cost_t total_cost = 0; 158 | cost_t reduce_sum = 0; 159 | 160 | auto process_path = [&]() -> void { 161 | flow_t path_cap = flow_goal - total_flow; 162 | cost_t cost_sum = 0; 163 | 164 | for (int node = sink; prv[node] != -1; node = prv[node]) 165 | path_cap = min(path_cap, prev_edge[node]->capacity); 166 | 167 | for (int node = sink; prv[node] != -1; node = prv[node]) { 168 | edge *e = prev_edge[node]; 169 | e->capacity -= path_cap; 170 | reverse_edge(*e).capacity += path_cap; 171 | cost_sum += e->cost; 172 | } 173 | 174 | total_flow += path_cap; 175 | total_cost += (reduce_sum + cost_sum) * path_cap; 176 | }; 177 | 178 | while (total_flow < flow_goal && bellman_ford(source, sink)) 179 | process_path(); 180 | 181 | if (too_much_bellman_ford) { 182 | do { 183 | reduce_cost(); 184 | reduce_sum += dist[sink]; 185 | process_path(); 186 | } while (total_flow < flow_goal && dijkstra(source, sink)); 187 | } 188 | 189 | return make_pair(total_flow, total_cost); 190 | } 191 | }; 192 | 193 | 194 | int main() { 195 | int N, M; 196 | cin >> N >> M; 197 | min_cost_flow graph(N); 198 | 199 | for (int i = 0; i < M; i++) { 200 | int a, b, cap, cost; 201 | cin >> a >> b >> cap >> cost; 202 | a--; b--; 203 | graph.add_directional_edge(a, b, cap, cost); 204 | } 205 | 206 | auto answer = graph.solve_min_cost_flow(0, N - 1); 207 | cout << answer.first << ' ' << answer.second << '\n'; 208 | } 209 | -------------------------------------------------------------------------------- /geometry/dp_hull.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // TODO: set this to false if it's unnecessary and the time limit might be tight. 9 | // CHECK_OVERFLOW64 = true can run up to 2 times slower (particularly on CF). 10 | const bool CHECK_OVERFLOW64 = true; 11 | 12 | struct point { 13 | int64_t x, y; 14 | 15 | point() : x(0), y(0) {} 16 | 17 | point(int64_t _x, int64_t _y) : x(_x), y(_y) {} 18 | 19 | point operator-(const point &other) const { 20 | return point(x - other.x, y - other.y); 21 | } 22 | }; 23 | 24 | int cross_sign(const point &a, const point &b) { 25 | if (CHECK_OVERFLOW64) { 26 | long double double_value = (long double) a.x * b.y - (long double) b.x * a.y; 27 | 28 | if (abs(double_value) > 1e18) 29 | return (double_value > 0) - (double_value < 0); 30 | } 31 | 32 | uint64_t uint64_value = (uint64_t) a.x * b.y - (uint64_t) b.x * a.y; 33 | int64_t actual = int64_t(uint64_value); 34 | return (actual > 0) - (actual < 0); 35 | } 36 | 37 | bool left_turn(const point &a, const point &b, const point &c) { 38 | return cross_sign(b - a, c - a) > 0; 39 | } 40 | 41 | // dp_hull enables you to do the following two operations in amortized O(log n) time: 42 | // 1. Insert a pair (a_i, b_i) into the structure 43 | // 2. For any value of x, query the maximum value of a_i * x + b_i 44 | // All values a_i, b_i, and x can be positive or negative. 45 | struct dp_hull { 46 | struct segment { 47 | point p; 48 | mutable point next_p; 49 | 50 | segment(point _p = {0, 0}) : p(_p), next_p(_p) {} 51 | 52 | // Note: this operator< supports `segments.lower_bound(point p)`. In order to support `upper_bound` as well, we 53 | // should also define `friend bool operator<(point p, segment s)`. 54 | bool operator<(const point &other) const { 55 | return (next_p.x - p.x) * other.x + (next_p.y - p.y) * other.y > 0; 56 | } 57 | 58 | bool operator<(const segment &other) const { 59 | return make_pair(p.x, p.y) < make_pair(other.p.x, other.p.y); 60 | } 61 | }; 62 | 63 | set> segments; 64 | 65 | int size() const { 66 | return int(segments.size()); 67 | } 68 | 69 | bool bad(set>::iterator it) const { 70 | if (it == segments.begin() || it == segments.end() || next(it) == segments.end()) 71 | return false; 72 | 73 | return !left_turn(next(it)->p, it->p, prev(it)->p); 74 | } 75 | 76 | void insert(const point &p) { 77 | auto next_it = segments.lower_bound(segment(p)); 78 | 79 | if (next_it != segments.end() && p.x == next_it->p.x) 80 | return; 81 | 82 | if (next_it != segments.begin()) { 83 | auto prev_it = prev(next_it); 84 | 85 | if (p.x == prev_it->p.x) 86 | segments.erase(prev_it); 87 | else if (next_it != segments.end() && !left_turn(next_it->p, p, prev_it->p)) 88 | return; 89 | } 90 | 91 | auto it = segments.insert(next_it, segment(p)); 92 | 93 | while (it != segments.begin() && bad(prev(it))) 94 | segments.erase(prev(it)); 95 | 96 | while (bad(next(it))) 97 | segments.erase(next(it)); 98 | 99 | if (it != segments.begin()) 100 | prev(it)->next_p = it->p; 101 | 102 | it->next_p = next(it) != segments.end() ? next(it)->p : it->p; 103 | } 104 | 105 | void insert(int64_t a, int64_t b) { 106 | insert(point(a, b)); 107 | } 108 | 109 | // Queries the maximum value of ax + by. 110 | int64_t query(int64_t x, int64_t y = 1) const { 111 | assert(size() > 0); 112 | assert(y > 0); 113 | auto it = segments.lower_bound(point(x, y)); 114 | return it->p.x * x + it->p.y * y; 115 | } 116 | }; 117 | 118 | 119 | int main() { 120 | int Q; 121 | scanf("%d", &Q); 122 | dp_hull hull; 123 | 124 | for (int q = 0; q < Q; q++) { 125 | int type; 126 | scanf("%d", &type); 127 | 128 | if (type == 1) { 129 | int a, b; 130 | scanf("%d %d", &a, &b); 131 | hull.insert(a, b); 132 | } else if (type == 2) { 133 | int x; 134 | scanf("%d", &x); 135 | printf("%lld\n", (long long) hull.query(2 * x, 2) / 2); 136 | } else { 137 | assert(false); 138 | } 139 | } 140 | 141 | cerr << "size: " << hull.size() << endl; 142 | } 143 | -------------------------------------------------------------------------------- /geometry/manhattan_mst.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const int INF = int(1e9) + 5; 9 | 10 | struct point { 11 | int64_t x, y; 12 | int index; 13 | 14 | point() : x(0), y(0), index(-INF) {} 15 | 16 | point(int64_t _x, int64_t _y, int _index = -INF) : x(_x), y(_y), index(_index) {} 17 | 18 | point& operator+=(const point &other) { x += other.x; y += other.y; return *this; } 19 | point& operator-=(const point &other) { x -= other.x; y -= other.y; return *this; } 20 | 21 | point operator+(const point &other) const { return point(*this) += other; } 22 | point operator-(const point &other) const { return point(*this) -= other; } 23 | 24 | bool operator==(const point &other) const { return x == other.x && y == other.y; } 25 | bool operator!=(const point &other) const { return !(*this == other); } 26 | 27 | point operator-() const { 28 | return point(-x, -y); 29 | } 30 | 31 | bool top_half() const { 32 | return y > 0 || (y == 0 && x > 0); 33 | } 34 | 35 | int64_t norm() const { 36 | return (int64_t) x * x + (int64_t) y * y; 37 | } 38 | 39 | double dist() const { 40 | return sqrt(norm()); 41 | } 42 | 43 | friend ostream& operator<<(ostream &os, const point &p) { 44 | return os << '(' << p.x << ", " << p.y << ')'; 45 | } 46 | }; 47 | 48 | int64_t manhattan_dist(const point &a, const point &b) { 49 | return (int64_t) abs(a.x - b.x) + abs(a.y - b.y); 50 | } 51 | 52 | // Sort in increasing order of y, with ties broken in increasing order of x. 53 | bool yx_compare(const point &a, const point &b) { 54 | return make_pair(a.y, a.x) < make_pair(b.y, b.x); 55 | } 56 | 57 | struct union_find { 58 | // When data[x] < 0, x is a root and -data[x] is its tree size. When data[x] >= 0, data[x] is x's parent. 59 | vector data; 60 | int components = 0; 61 | 62 | union_find(int n = -1) { 63 | if (n >= 0) 64 | init(n); 65 | } 66 | 67 | void init(int n) { 68 | data.assign(n, -1); 69 | components = n; 70 | } 71 | 72 | int find(int x) { 73 | return data[x] < 0 ? x : data[x] = find(data[x]); 74 | } 75 | 76 | int get_size(int x) { 77 | return -data[find(x)]; 78 | } 79 | 80 | bool unite(int x, int y) { 81 | x = find(x); 82 | y = find(y); 83 | 84 | if (x == y) 85 | return false; 86 | 87 | if (-data[x] < -data[y]) 88 | swap(x, y); 89 | 90 | data[x] += data[y]; 91 | data[y] = x; 92 | components--; 93 | return true; 94 | } 95 | }; 96 | 97 | 98 | struct edge { 99 | int index1, index2; 100 | int64_t dist; 101 | 102 | edge() {} 103 | 104 | edge(int _index1, int _index2, int64_t _dist) : index1(_index1), index2(_index2), dist(_dist) {} 105 | 106 | bool operator<(const edge &other) const { 107 | return dist < other.dist; 108 | } 109 | }; 110 | 111 | point rotate90(point p) { 112 | swap(p.x, p.y); 113 | p.x = -p.x; 114 | return p; 115 | } 116 | 117 | void rotate_all(vector &points) { 118 | for (point &p : points) 119 | p = rotate90(p); 120 | } 121 | 122 | void swap_all(vector &points) { 123 | for (point &p : points) 124 | swap(p.x, p.y); 125 | } 126 | 127 | bool has_better_sum(const point &a, const point &b) { 128 | if (a.index < 0) 129 | return false; 130 | 131 | if (b.index < 0) 132 | return true; 133 | 134 | return a.x + a.y < b.x + b.y; 135 | } 136 | 137 | vector buffer, c_buffer; 138 | 139 | void solve(vector &points, vector &closest, int start, int end) { 140 | if (end - start <= 1) 141 | return; 142 | 143 | int mid = (start + end) / 2; 144 | solve(points, closest, start, mid); 145 | solve(points, closest, mid, end); 146 | int right = mid, n = 0; 147 | point min_sum; 148 | 149 | // Merge sort by y - x, and keep track of the smallest x + y point we've seen so far. 150 | // Thus for each left point, we find the right point with the minimum value of x + y that satisfies 151 | // yx_compare(left, right) = true and right.y - right.x <= left.y - left.x. 152 | for (int i = start; i < mid; i++) { 153 | while (right < end && points[right].y - points[right].x <= points[i].y - points[i].x) { 154 | buffer[n] = points[right]; 155 | c_buffer[n] = closest[right]; 156 | 157 | if (has_better_sum(points[right], min_sum)) 158 | min_sum = points[right]; 159 | 160 | n++; 161 | right++; 162 | } 163 | 164 | if (has_better_sum(min_sum, closest[i])) 165 | closest[i] = min_sum; 166 | 167 | buffer[n] = points[i]; 168 | c_buffer[n] = closest[i]; 169 | n++; 170 | } 171 | 172 | // Copy the results back in their sorted order. 173 | copy(buffer.begin(), buffer.begin() + n, points.begin() + start); 174 | copy(c_buffer.begin(), c_buffer.begin() + n, closest.begin() + start); 175 | } 176 | 177 | vector manhattan_mst(vector points) { 178 | int N = int(points.size()); 179 | vector closest; 180 | vector edges; 181 | 182 | buffer.resize(N); 183 | c_buffer.resize(N); 184 | 185 | // We find four edges for each point: one to the closest point in each of the four octants on the point's right. 186 | for (int rep = 0; rep < 4; rep++) { 187 | sort(points.begin(), points.end(), yx_compare); 188 | closest.assign(N, point()); 189 | 190 | // For each point (x, y), find the closest point (x', y') such that y' >= y and y' - x' <= y - x. 191 | // In other words, this finds the closest point in the octant to the right of the point and slightly above. 192 | // See https://www.topcoder.com/community/competitive-programming/tutorials/line-sweep-algorithms/ for details. 193 | solve(points, closest, 0, N); 194 | 195 | for (int i = 0; i < N; i++) 196 | if (closest[i].index >= 0) 197 | edges.emplace_back(points[i].index, closest[i].index, manhattan_dist(points[i], closest[i])); 198 | 199 | if (rep % 2 == 0) 200 | swap_all(points); 201 | else 202 | rotate_all(points); 203 | } 204 | 205 | // To return the points back to normal: 206 | // rotate_all(points); rotate_all(points); 207 | 208 | sort(edges.begin(), edges.end()); 209 | union_find UF(N); 210 | vector mst; 211 | 212 | for (edge &e : edges) 213 | if (UF.unite(e.index1, e.index2)) 214 | mst.push_back(e); 215 | 216 | return mst; 217 | } 218 | 219 | int main() { 220 | ios::sync_with_stdio(false); 221 | #ifndef NEAL_DEBUG 222 | cin.tie(nullptr); 223 | #endif 224 | 225 | int N; 226 | cin >> N; 227 | vector points(N); 228 | 229 | for (point &p : points) 230 | cin >> p.x >> p.y; 231 | 232 | for (int i = 0; i < N; i++) 233 | points[i].index = i; 234 | 235 | vector mst = manhattan_mst(points); 236 | assert(int(mst.size()) == max(N - 1, 0)); 237 | int64_t total = 0; 238 | 239 | for (edge &e : mst) 240 | total += e.dist; 241 | 242 | cout << total << '\n'; 243 | } 244 | -------------------------------------------------------------------------------- /geometry/monotonic_dp_hull_deque.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // TODO: set this to false if it's unnecessary and the time limit might be tight. 9 | // CHECK_OVERFLOW64 = true can run up to 2 times slower (particularly on CF). 10 | const bool CHECK_OVERFLOW64 = true; 11 | 12 | struct point { 13 | int64_t x, y; 14 | 15 | point() : x(0), y(0) {} 16 | 17 | point(int64_t _x, int64_t _y) : x(_x), y(_y) {} 18 | 19 | point operator-(const point &other) const { 20 | return point(x - other.x, y - other.y); 21 | } 22 | }; 23 | 24 | int cross_sign(const point &a, const point &b) { 25 | if (CHECK_OVERFLOW64) { 26 | long double double_value = (long double) a.x * b.y - (long double) b.x * a.y; 27 | 28 | if (abs(double_value) > 1e18) 29 | return (double_value > 0) - (double_value < 0); 30 | } 31 | 32 | uint64_t uint64_value = (uint64_t) a.x * b.y - (uint64_t) b.x * a.y; 33 | int64_t actual = int64_t(uint64_value); 34 | return (actual > 0) - (actual < 0); 35 | } 36 | 37 | bool left_turn(const point &a, const point &b, const point &c) { 38 | return cross_sign(b - a, c - a) > 0; 39 | } 40 | 41 | const int64_t INF64 = int64_t(2e18) + 5; 42 | 43 | // monotonic_dp_hull enables you to do the following two operations in amortized O(1) time: 44 | // 1. Insert a pair (a_i, b_i) into the structure. a_i must be non-decreasing. 45 | // 2. For any value of x, query the maximum value of a_i * x + b_i. x must be non-decreasing. 46 | // All values a_i, b_i, and x can be positive or negative. 47 | struct monotonic_dp_hull { 48 | deque points; 49 | 50 | void clear() { 51 | points.clear(); 52 | prev_x = -INF64; 53 | prev_y = 1; 54 | } 55 | 56 | int size() const { 57 | return int(points.size()); 58 | } 59 | 60 | void insert(const point &p) { 61 | assert(points.empty() || p.x >= points.back().x); 62 | 63 | if (!points.empty() && p.x == points.back().x) { 64 | if (p.y <= points.back().y) 65 | return; 66 | 67 | points.pop_back(); 68 | } 69 | 70 | while (size() >= 2 && !left_turn(p, points.back(), points[size() - 2])) 71 | points.pop_back(); 72 | 73 | points.push_back(p); 74 | } 75 | 76 | void insert(int64_t a, int64_t b) { 77 | insert(point(a, b)); 78 | } 79 | 80 | int64_t prev_x = -INF64, prev_y = 1; 81 | 82 | // Queries the maximum value of ax + by. 83 | int64_t query(int64_t x, int64_t y = 1) { 84 | assert(size() > 0); 85 | assert(y > 0); 86 | assert(prev_x == -INF64 || x * prev_y >= prev_x * y); 87 | prev_x = x; prev_y = y; 88 | 89 | while (size() >= 2 && (points[1].x - points[0].x) * x + (points[1].y - points[0].y) * y >= 0) 90 | points.pop_front(); 91 | 92 | return points[0].x * x + points[0].y * y; 93 | } 94 | }; 95 | 96 | 97 | int main() { 98 | int Q; 99 | scanf("%d", &Q); 100 | monotonic_dp_hull hull; 101 | 102 | for (int q = 0; q < Q; q++) { 103 | int type; 104 | scanf("%d", &type); 105 | 106 | if (type == 1) { 107 | int a, b; 108 | scanf("%d %d", &a, &b); 109 | hull.insert(a, b); 110 | } else if (type == 2) { 111 | int x; 112 | scanf("%d", &x); 113 | printf("%lld\n", (long long) hull.query(2 * x, 2) / 2); 114 | } else { 115 | assert(false); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /geometry/online_hull.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | using coord_t = int; 9 | 10 | // Maintains the upper hull for coordinates that can span a range of roughly [-1e9, 1e9]. 11 | struct upper_hull { 12 | map points; 13 | int64_t area = 0; 14 | 15 | int size() const { 16 | return int(points.size()); 17 | } 18 | 19 | int64_t cross(coord_t x1, coord_t y1, coord_t x2, coord_t y2) const { 20 | return (int64_t) x1 * y2 - (int64_t) x2 * y1; 21 | } 22 | 23 | // Note: all areas are signed and doubled. For triangles, clockwise (not counter-clockwise) is positive. 24 | 25 | int64_t trapezoid_area(coord_t x1, coord_t y1, coord_t x2, coord_t y2) const { 26 | return (int64_t) (x2 - x1) * (y1 + y2); 27 | } 28 | 29 | int64_t trapezoid_area(pair p1, pair p2) const { 30 | return trapezoid_area(p1.first, p1.second, p2.first, p2.second); 31 | } 32 | 33 | int64_t triangle_area(coord_t x1, coord_t y1, coord_t x2, coord_t y2, coord_t x3, coord_t y3) const { 34 | return cross(x2 - x1, y2 - y1, x2 - x3, y2 - y3); 35 | } 36 | 37 | int64_t triangle_area(pair p1, pair p2, pair p3) const { 38 | return triangle_area(p1.first, p1.second, p2.first, p2.second, p3.first, p3.second); 39 | } 40 | 41 | // Gets the area that a point is responsible for; that is, how much area would be lost if the point were removed. 42 | int64_t point_area(map::iterator it) { 43 | bool has_prev = it != points.begin(); 44 | bool has_next = next(it) != points.end(); 45 | 46 | if (has_prev && has_next) 47 | return triangle_area(*prev(it), *it, *next(it)); 48 | 49 | int64_t sum = 0; 50 | 51 | if (has_prev) 52 | sum += trapezoid_area(*prev(it), *it); 53 | 54 | if (has_next) 55 | sum += trapezoid_area(*it, *next(it)); 56 | 57 | return sum; 58 | } 59 | 60 | bool bad(map::iterator it) { 61 | if (it == points.begin() || it == points.end() || next(it) == points.end()) 62 | return false; 63 | 64 | // True if the three points form a left turn or line up straight. 65 | return point_area(it) <= 0; 66 | } 67 | 68 | void erase(map::iterator it) { 69 | area -= point_area(it); 70 | points.erase(it); 71 | } 72 | 73 | bool insert(coord_t x, coord_t y) { 74 | if (points.find(x) != points.end()) { 75 | if (y <= points[x]) 76 | return false; 77 | 78 | erase(points.find(x)); 79 | } 80 | 81 | map::iterator it = points.insert(make_pair(x, y)).first; 82 | 83 | if (bad(it)) { 84 | points.erase(it); 85 | return false; 86 | } 87 | 88 | area += point_area(it); 89 | 90 | while (it != points.begin() && bad(prev(it))) 91 | erase(prev(it)); 92 | 93 | while (bad(next(it))) 94 | erase(next(it)); 95 | 96 | return true; 97 | } 98 | 99 | // Returns 1 for strictly contained, 0 for on the border, and -1 for not contained. 100 | int contains(coord_t x, coord_t y) const { 101 | if (points.empty()) 102 | return -1; 103 | 104 | map::const_iterator first = points.begin(), last = prev(points.end()); 105 | 106 | if (x < first->first || x > last->first) 107 | return -1; 108 | 109 | if (x == first->first) 110 | return y <= first->second ? 0 : -1; 111 | 112 | if (x == last->first) 113 | return y <= last->second ? 0 : -1; 114 | 115 | map::const_iterator it = points.lower_bound(x); 116 | int64_t a = triangle_area(*prev(it), make_pair(x, y), *it); 117 | return a == 0 ? 0 : (a > 0 ? -1 : 1); 118 | } 119 | }; 120 | 121 | // The combined hull with both upper and lower. 122 | struct online_hull { 123 | upper_hull upper, lower; 124 | 125 | int64_t get_area_doubled() const { 126 | return upper.area + lower.area; 127 | } 128 | 129 | bool insert(coord_t x, coord_t y) { 130 | bool upper_insert = upper.insert(x, y); 131 | bool lower_insert = lower.insert(x, -y); 132 | return upper_insert || lower_insert; 133 | } 134 | 135 | int contains(coord_t x, coord_t y) const { 136 | int upper_contains = upper.contains(x, y); 137 | int lower_contains = lower.contains(x, -y); 138 | return min(upper_contains, lower_contains); 139 | } 140 | }; 141 | 142 | online_hull hull; 143 | 144 | int main() { 145 | ios::sync_with_stdio(false); 146 | #ifndef NEAL_DEBUG 147 | cin.tie(nullptr); 148 | #endif 149 | 150 | int type, x, y; 151 | 152 | while (cin >> type >> x >> y) { 153 | if (type == 1) { 154 | hull.insert(x, y); 155 | cout << hull.get_area_doubled() << '\n'; 156 | } else if (type == 2) { 157 | int contains = hull.contains(x, y); 158 | cout << (contains == 0 ? "border" : (contains > 0 ? "inside" : "outside")) << '\n'; 159 | } else { 160 | assert(false); 161 | } 162 | } 163 | 164 | cerr << "Hull size: " << hull.upper.size() + hull.lower.size() << '\n'; 165 | } 166 | -------------------------------------------------------------------------------- /geometry/point.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | // TODO: set this to false if it's unnecessary and the time limit might be tight. 10 | // CHECK_OVERFLOW64 = true can run up to 2 times slower (particularly on CF). 11 | const bool CHECK_OVERFLOW64 = true; 12 | 13 | using dist_t = long double; 14 | 15 | struct point { 16 | int64_t x, y; 17 | 18 | point() : x(0), y(0) {} 19 | 20 | point(int64_t _x, int64_t _y) : x(_x), y(_y) {} 21 | 22 | point& operator+=(const point &other) { x += other.x; y += other.y; return *this; } 23 | point& operator-=(const point &other) { x -= other.x; y -= other.y; return *this; } 24 | point& operator*=(int64_t mult) { x *= mult; y *= mult; return *this; } 25 | 26 | point operator+(const point &other) const { return point(*this) += other; } 27 | point operator-(const point &other) const { return point(*this) -= other; } 28 | point operator*(int64_t mult) const { return point(*this) *= mult; } 29 | 30 | bool operator==(const point &other) const { return x == other.x && y == other.y; } 31 | bool operator!=(const point &other) const { return !(*this == other); } 32 | 33 | point operator-() const { return point(-x, -y); } 34 | point rotate90() const { return point(-y, x); } 35 | 36 | int64_t norm() const { 37 | return (int64_t) x * x + (int64_t) y * y; 38 | } 39 | 40 | dist_t dist() const { 41 | return sqrt(dist_t(norm())); 42 | } 43 | 44 | bool top_half() const { 45 | return y > 0 || (y == 0 && x > 0); 46 | } 47 | 48 | friend ostream& operator<<(ostream &os, const point &p) { 49 | return os << '(' << p.x << ", " << p.y << ')'; 50 | } 51 | }; 52 | 53 | int64_t cross(const point &a, const point &b) { 54 | return (int64_t) a.x * b.y - (int64_t) b.x * a.y; 55 | } 56 | 57 | int64_t dot(const point &a, const point &b) { 58 | return (int64_t) a.x * b.x + (int64_t) a.y * b.y; 59 | } 60 | 61 | int cross_sign(const point &a, const point &b) { 62 | if (CHECK_OVERFLOW64) { 63 | long double double_value = (long double) a.x * b.y - (long double) b.x * a.y; 64 | 65 | if (abs(double_value) > 1e18) 66 | return (double_value > 0) - (double_value < 0); 67 | } 68 | 69 | uint64_t uint64_value = (uint64_t) a.x * b.y - (uint64_t) b.x * a.y; 70 | int64_t actual = int64_t(uint64_value); 71 | return (actual > 0) - (actual < 0); 72 | } 73 | 74 | bool left_turn_strict(const point &a, const point &b, const point &c) { 75 | return cross_sign(b - a, c - a) > 0; 76 | } 77 | 78 | bool left_turn_lenient(const point &a, const point &b, const point &c) { 79 | return cross_sign(b - a, c - a) >= 0; 80 | } 81 | 82 | bool collinear(const point &a, const point &b, const point &c) { 83 | return cross_sign(b - a, c - a) == 0; 84 | } 85 | 86 | // Returns twice the signed area formed by three points in a triangle. Positive when a -> b -> c is a left turn. 87 | int64_t area_signed_2x(const point &a, const point &b, const point &c) { 88 | return cross(b - a, c - a); 89 | } 90 | 91 | dist_t distance_to_line(const point &p, const point &a, const point &b) { 92 | assert(a != b); 93 | return dist_t(abs(area_signed_2x(p, a, b))) / (a - b).dist(); 94 | } 95 | 96 | int64_t manhattan_dist(const point &a, const point &b) { 97 | return (int64_t) abs(a.x - b.x) + abs(a.y - b.y); 98 | } 99 | 100 | int64_t infinity_norm_dist(const point &a, const point &b) { 101 | return max(abs(a.x - b.x), abs(a.y - b.y)); 102 | } 103 | 104 | // Sort in increasing order of y, with ties broken in increasing order of x. 105 | bool yx_compare(const point &a, const point &b) { 106 | return make_pair(a.y, a.x) < make_pair(b.y, b.x); 107 | } 108 | 109 | // Sort in increasing order of angle to the x-axis. 110 | bool angle_compare(const point &a, const point &b) { 111 | if (a.top_half() ^ b.top_half()) 112 | return a.top_half(); 113 | 114 | return cross_sign(a, b) > 0; 115 | } 116 | -------------------------------------------------------------------------------- /graph_theory/bridges.cc: -------------------------------------------------------------------------------- 1 | // Solution to https://leetcode.com/contest/weekly-contest-154/problems/critical-connections-in-a-network/ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | template ostream& operator<<(ostream &os, const vector &v) { os << "{"; string sep; for (const auto &x : v) os << sep << x, sep = ", "; return os << "}"; } 10 | 11 | struct find_bridges { 12 | struct edge { 13 | int node, index; 14 | 15 | edge() {} 16 | 17 | edge(int _node, int _index) : node(_node), index(_index) {} 18 | }; 19 | 20 | int n, edges; 21 | vector> adj; 22 | vector> edge_list; 23 | vector tour_start; 24 | vector low_link; 25 | vector visited; 26 | vector is_bridge; 27 | int tour; 28 | 29 | find_bridges(int _n = 0) { 30 | init(_n); 31 | } 32 | 33 | void init(int _n) { 34 | n = _n; 35 | edges = 0; 36 | adj.assign(n, {}); 37 | edge_list.clear(); 38 | tour_start.resize(n); 39 | low_link.resize(n); 40 | } 41 | 42 | void add_edge(int a, int b) { 43 | adj[a].emplace_back(b, edges); 44 | adj[b].emplace_back(a, edges); 45 | edge_list.push_back({a, b}); 46 | edges++; 47 | } 48 | 49 | void dfs(int node, int parent_edge) { 50 | assert(!visited[node]); 51 | visited[node] = true; 52 | tour_start[node] = tour++; 53 | low_link[node] = tour_start[node]; 54 | 55 | for (edge &e : adj[node]) { 56 | // Skip the previous edge to the parent, but allow multi-edges. 57 | if (e.index == parent_edge) 58 | continue; 59 | 60 | if (visited[e.node]) { 61 | // e.node is a candidate for low_link. 62 | low_link[node] = min(low_link[node], tour_start[e.node]); 63 | } else { 64 | // e.node is part of our subtree. 65 | dfs(e.node, e.index); 66 | low_link[node] = min(low_link[node], low_link[e.node]); 67 | is_bridge[e.index] = low_link[e.node] > tour_start[node]; 68 | } 69 | } 70 | } 71 | 72 | void solve() { 73 | visited.assign(n, false); 74 | is_bridge.assign(edges, false); 75 | tour = 0; 76 | 77 | for (int i = 0; i < n; i++) 78 | if (!visited[i]) 79 | dfs(i, -1); 80 | } 81 | }; 82 | 83 | 84 | class Solution { 85 | public: 86 | vector> criticalConnections(int n, vector>& connections) { 87 | find_bridges graph(n); 88 | int E = int(connections.size()); 89 | 90 | for (int e = 0; e < E; e++) { 91 | int a = connections[e][0], b = connections[e][1]; 92 | graph.add_edge(a, b); 93 | } 94 | 95 | graph.solve(); 96 | 97 | // Construct the bridge list in the same order as given in the input. 98 | vector> bridge_list; 99 | 100 | for (int e = 0; e < E; e++) 101 | if (graph.is_bridge[e]) 102 | bridge_list.push_back(connections[e]); 103 | 104 | return bridge_list; 105 | } 106 | }; 107 | 108 | int main() { 109 | ios::sync_with_stdio(false); 110 | #ifndef NEAL_DEBUG 111 | cin.tie(nullptr); 112 | #endif 113 | 114 | vector> connections; 115 | vector> desired; 116 | 117 | connections = {{0, 1}, {1, 2}, {2, 0}, {1, 3}}; 118 | desired = {{1, 3}}; 119 | assert(Solution().criticalConnections(4, connections) == desired); 120 | 121 | connections = {{0, 1}, {1, 2}, {1, 3}, {4, 3}}; 122 | desired = {{0, 1}, {1, 2}, {1, 3}, {4, 3}}; 123 | assert(Solution().criticalConnections(5, connections) == desired); 124 | 125 | connections = {{0, 1}, {1, 2}, {2, 0}, {1, 3}, {3, 4}, {4, 5}, {5, 3}}; 126 | desired = {{1, 3}}; 127 | assert(Solution().criticalConnections(6, connections) == desired); 128 | 129 | cerr << "Tests passed!" << endl; 130 | 131 | int n, m; 132 | cin >> n >> m; 133 | connections = {}; 134 | 135 | for (int i = 0; i < m; i++) { 136 | int a, b; 137 | cin >> a >> b; 138 | connections.push_back({a, b}); 139 | } 140 | 141 | vector> answer = Solution().criticalConnections(n, connections); 142 | 143 | for (auto &e : answer) { 144 | assert(e.size() == 2); 145 | cout << e[0] << ' ' << e[1] << '\n'; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /graph_theory/check_bipartite.cc: -------------------------------------------------------------------------------- 1 | 2 | struct check_bipartite { 3 | int V; 4 | vector> adj; 5 | vector depth; 6 | vector visited; 7 | 8 | check_bipartite(int v = -1) { 9 | if (v >= 0) 10 | init(v); 11 | } 12 | 13 | void init(int v) { 14 | V = v; 15 | adj.assign(V, {}); 16 | } 17 | 18 | void add_edge(int a, int b) { 19 | adj[a].push_back(b); 20 | adj[b].push_back(a); 21 | } 22 | 23 | vector, 2>> components; 24 | 25 | bool dfs(int node, int parent) { 26 | assert(!visited[node]); 27 | visited[node] = true; 28 | depth[node] = parent < 0 ? 0 : depth[parent] + 1; 29 | components.back()[depth[node] % 2].push_back(node); 30 | 31 | for (int neigh : adj[node]) 32 | if (neigh != parent) { 33 | if (!visited[neigh] && !dfs(neigh, node)) 34 | return false; 35 | 36 | if (depth[node] % 2 == depth[neigh] % 2) 37 | return false; 38 | } 39 | 40 | return true; 41 | } 42 | 43 | // Returns true iff the graph is bipartite. 44 | // Also builds a vector of components, where each component is divided into its two parts. 45 | bool solve() { 46 | depth.assign(V, -1); 47 | visited.assign(V, false); 48 | components = {}; 49 | 50 | for (int i = 0; i < V; i++) 51 | if (!visited[i]) { 52 | components.emplace_back(); 53 | 54 | if (!dfs(i, -1)) 55 | return false; 56 | } 57 | 58 | return true; 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /graph_theory/topological_sort.cc: -------------------------------------------------------------------------------- 1 | 2 | // Note: if there is a cycle, the size of the return will be less than n. 3 | vector topological_sort(const vector> &adj) { 4 | int n = int(adj.size()); 5 | vector in_degree(n, 0); 6 | vector order; 7 | 8 | for (int i = 0; i < n; i++) 9 | for (int neighbor : adj[i]) 10 | in_degree[neighbor]++; 11 | 12 | for (int i = 0; i < n; i++) 13 | if (in_degree[i] == 0) 14 | order.push_back(i); 15 | 16 | int current = 0; 17 | 18 | while (current < int(order.size())) { 19 | int node = order[current++]; 20 | 21 | for (int neighbor : adj[node]) 22 | if (--in_degree[neighbor] == 0) 23 | order.push_back(neighbor); 24 | } 25 | 26 | return order; 27 | } 28 | -------------------------------------------------------------------------------- /hash/array_hash.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | uint64_t random_address() { char *p = new char; delete p; return uint64_t(p); } 10 | 11 | uint64_t splitmix64(uint64_t x) { 12 | // http://xorshift.di.unimi.it/splitmix64.c 13 | x += 0x9e3779b97f4a7c15; 14 | x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; 15 | x = (x ^ (x >> 27)) * 0x94d049bb133111eb; 16 | return x ^ (x >> 31); 17 | } 18 | 19 | const uint64_t FIXED_RANDOM = splitmix64(chrono::steady_clock::now().time_since_epoch().count() * (random_address() | 1)); 20 | 21 | template 22 | struct array_hash { 23 | using hash_t = uint64_t; 24 | 25 | int n; 26 | vector arr; 27 | hash_t hash; 28 | 29 | array_hash(int _n = 0) { 30 | init(_n); 31 | } 32 | 33 | array_hash(const vector &_arr) { 34 | init(_arr); 35 | } 36 | 37 | hash_t get_hash(int index) const { 38 | assert(0 <= index && index < n); 39 | // This ties arr[index] closely with index and ensures we call splitmix64 in between any two arithmetic operations. 40 | return splitmix64(arr[index] ^ splitmix64(index ^ FIXED_RANDOM)); 41 | } 42 | 43 | void compute_hash() { 44 | hash = 0; 45 | 46 | for (int i = 0; i < n; i++) 47 | hash += get_hash(i); 48 | } 49 | 50 | void init(int _n) { 51 | n = _n; 52 | arr.assign(n, 0); 53 | compute_hash(); 54 | } 55 | 56 | void init(const vector &_arr) { 57 | arr = _arr; 58 | n = int(arr.size()); 59 | compute_hash(); 60 | } 61 | 62 | const T& operator[](int index) const { 63 | return arr[index]; 64 | } 65 | 66 | void modify(int index, const T &value) { 67 | hash -= get_hash(index); 68 | arr[index] = value; 69 | hash += get_hash(index); 70 | } 71 | }; 72 | 73 | 74 | #include 75 | using namespace __gnu_pbds; 76 | 77 | int main() { 78 | int N, Q; 79 | cin >> N >> Q; 80 | vector A(N); 81 | 82 | for (auto &a : A) 83 | cin >> a; 84 | 85 | array_hash hasher(A); 86 | gp_hash_table hashes; 87 | hashes.insert(hasher.hash); 88 | 89 | for (int q = 0; q < Q; q++) { 90 | int index; 91 | int64_t value; 92 | cin >> index >> value; 93 | index--; 94 | hasher.modify(index, value); 95 | assert(hasher[index] == value); 96 | hashes.insert(hasher.hash); 97 | cout << hashes.size() << '\n'; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /io/io.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | namespace IO { 9 | const int BUFFER_SIZE = 1 << 15; 10 | 11 | char input_buffer[BUFFER_SIZE]; 12 | size_t input_pos = 0, input_len = 0; 13 | 14 | char output_buffer[BUFFER_SIZE]; 15 | int output_pos = 0; 16 | 17 | char number_buffer[100]; 18 | uint8_t lookup[100]; 19 | 20 | void _update_input_buffer() { 21 | input_len = fread(input_buffer, sizeof(char), BUFFER_SIZE, stdin); 22 | input_pos = 0; 23 | 24 | if (input_len == 0) 25 | input_buffer[0] = EOF; 26 | } 27 | 28 | inline char next_char(bool advance = true) { 29 | if (input_pos >= input_len) 30 | _update_input_buffer(); 31 | 32 | return input_buffer[advance ? input_pos++ : input_pos]; 33 | } 34 | 35 | inline bool isspace(char c) { 36 | return (unsigned char) (c - '\t') < 5 || c == ' '; 37 | } 38 | 39 | inline bool input_finished() { 40 | while (isspace(next_char(false)) && input_len > 0) 41 | next_char(); 42 | 43 | return input_len < BUFFER_SIZE && input_pos >= input_len; 44 | } 45 | 46 | inline void read_char(char &c) { 47 | while (isspace(next_char(false))) 48 | next_char(); 49 | 50 | c = next_char(); 51 | } 52 | 53 | template 54 | inline void read_int(T &number) { 55 | bool negative = false; 56 | number = 0; 57 | 58 | while (!isdigit(next_char(false))) 59 | if (next_char() == '-') 60 | negative = true; 61 | 62 | do { 63 | number = 10 * number + (next_char() - '0'); 64 | } while (isdigit(next_char(false))); 65 | 66 | if (negative) 67 | number = -number; 68 | } 69 | 70 | template 71 | inline void read_int(T &number, Args &... args) { 72 | read_int(number); 73 | read_int(args...); 74 | } 75 | 76 | inline void read_double(double &number) { 77 | bool negative = false; 78 | number = 0; 79 | 80 | while (!isdigit(next_char(false))) 81 | if (next_char() == '-') 82 | negative = true; 83 | 84 | do { 85 | number = 10 * number + (next_char() - '0'); 86 | } while (isdigit(next_char(false))); 87 | 88 | if (next_char(false) == '.') { 89 | next_char(); 90 | 91 | for (double multiplier = 0.1; isdigit(next_char(false)); multiplier *= 0.1) 92 | number += multiplier * (next_char() - '0'); 93 | } 94 | 95 | if (negative) 96 | number = -number; 97 | } 98 | 99 | inline void read_str(string &str) { 100 | while (isspace(next_char(false))) 101 | next_char(); 102 | 103 | str.clear(); 104 | 105 | do { 106 | str += next_char(); 107 | } while (!isspace(next_char(false))); 108 | } 109 | 110 | inline void read_line(string &str) { 111 | while (next_char(false) == '\n') 112 | next_char(); 113 | 114 | str.clear(); 115 | 116 | do { 117 | str += next_char(); 118 | } while (next_char(false) != '\n'); 119 | } 120 | 121 | void _flush_output() { 122 | fwrite(output_buffer, sizeof(char), output_pos, stdout); 123 | output_pos = 0; 124 | } 125 | 126 | inline void write_char(char c) { 127 | if (output_pos == BUFFER_SIZE) 128 | _flush_output(); 129 | 130 | output_buffer[output_pos++] = c; 131 | } 132 | 133 | template 134 | inline void write_int(T number, char after = '\0') { 135 | if (number < 0) { 136 | write_char('-'); 137 | number = -number; 138 | } 139 | 140 | int length = 0; 141 | 142 | while (number >= 10) { 143 | uint8_t lookup_value = lookup[number % 100]; 144 | number /= 100; 145 | number_buffer[length++] = char((lookup_value & 15) + '0'); 146 | number_buffer[length++] = char((lookup_value >> 4) + '0'); 147 | } 148 | 149 | if (number != 0 || length == 0) 150 | write_char(char(number + '0')); 151 | 152 | for (int i = length - 1; i >= 0; i--) 153 | write_char(number_buffer[i]); 154 | 155 | if (after) 156 | write_char(after); 157 | } 158 | 159 | inline void write_str(const string &str, char after = '\0') { 160 | for (char c : str) 161 | write_char(c); 162 | 163 | if (after) 164 | write_char(after); 165 | } 166 | 167 | inline void write_double(double number, char after = '\0', int places = 6) { 168 | if (number < 0) { 169 | write_char('-'); 170 | number = -number; 171 | } 172 | 173 | assert(number <= 9e18); 174 | 175 | // Round up the number according to places. 176 | number += 0.5 * pow(0.1, places); 177 | int64_t floored = int64_t(number); 178 | 179 | if (floored <= numeric_limits::max()) 180 | write_int(int(floored)); 181 | else 182 | write_int(floored); 183 | 184 | number -= double(floored); 185 | 186 | if (number < 0 || number >= 1) 187 | number = 0; 188 | 189 | if (places > 0) { 190 | write_char('.'); 191 | 192 | while (places >= 2) { 193 | number *= 100; 194 | int two = int(number); 195 | number -= two; 196 | uint8_t lookup_value = lookup[two]; 197 | write_char(char((lookup_value >> 4) + '0')); 198 | write_char(char((lookup_value & 15) + '0')); 199 | places -= 2; 200 | } 201 | 202 | if (places == 1) { 203 | number *= 10; 204 | int one = int(number); 205 | write_char(char(one + '0')); 206 | } 207 | } 208 | 209 | if (after) 210 | write_char(after); 211 | } 212 | 213 | void init() { 214 | // Ensures that _flush_output() is called at the end of the program. 215 | bool exit_success = atexit(_flush_output) == 0; 216 | assert(exit_success); 217 | 218 | for (int i = 0; i < 100; i++) 219 | lookup[i] = uint8_t((i / 10 << 4) + i % 10); 220 | } 221 | } 222 | 223 | 224 | int main() { 225 | IO::init(); 226 | 227 | while (!IO::input_finished()) { 228 | int type; 229 | IO::read_int(type); 230 | assert(1 <= type && type <= 3); 231 | 232 | if (type == 1) { 233 | int64_t n; 234 | IO::read_int(n); 235 | IO::write_int(2 * n, '\n'); 236 | } else if (type == 2) { 237 | double d; 238 | IO::read_double(d); 239 | IO::write_double(2 * d, '\n'); 240 | } else if (type == 3) { 241 | string str; 242 | IO::read_str(str); 243 | reverse(str.begin(), str.end()); 244 | IO::write_str(str, '\n'); 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /miscellaneous/closest_left_right.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // For every i, finds the largest j < i such that `compare(values[j], values[i])` is true, or -1 if no such j exists. 9 | template 10 | vector closest_left(const vector &values, T_compare &&compare) { 11 | int n = int(values.size()); 12 | vector closest(n); 13 | vector stack; 14 | 15 | for (int i = 0; i < n; i++) { 16 | while (!stack.empty() && !compare(values[stack.back()], values[i])) 17 | stack.pop_back(); 18 | 19 | closest[i] = stack.empty() ? -1 : stack.back(); 20 | stack.push_back(i); 21 | } 22 | 23 | return closest; 24 | } 25 | 26 | // For every i, finds the smallest j > i such that `compare(values[j], values[i])` is true, or `n` if no such j exists. 27 | template 28 | vector closest_right(const vector &values, T_compare &&compare) { 29 | int n = int(values.size()); 30 | vector closest(n); 31 | vector stack; 32 | 33 | for (int i = n - 1; i >= 0; i--) { 34 | while (!stack.empty() && !compare(values[stack.back()], values[i])) 35 | stack.pop_back(); 36 | 37 | closest[i] = stack.empty() ? n : stack.back(); 38 | stack.push_back(i); 39 | } 40 | 41 | return closest; 42 | } 43 | 44 | 45 | int main() { 46 | ios::sync_with_stdio(false); 47 | #ifndef NEAL_DEBUG 48 | cin.tie(nullptr); 49 | #endif 50 | 51 | int N; 52 | cin >> N; 53 | vector values(N); 54 | 55 | for (auto &v : values) 56 | cin >> v; 57 | 58 | auto output_closest = [&](auto compare) -> void { 59 | vector left = closest_left(values, compare); 60 | vector right = closest_right(values, compare); 61 | 62 | for (int i = 0; i < N; i++) 63 | cout << left[i] << ' ' << right[i] << '\n'; 64 | 65 | cout << '\n'; 66 | }; 67 | 68 | output_closest(less()); 69 | output_closest(greater()); 70 | output_closest(less_equal()); 71 | output_closest(greater_equal()); 72 | } 73 | -------------------------------------------------------------------------------- /miscellaneous/compress_array.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | using namespace std; 20 | 21 | // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0200r0.html 22 | template class y_combinator_result { 23 | Fun fun_; 24 | public: 25 | template explicit y_combinator_result(T &&fun): fun_(std::forward(fun)) {} 26 | template decltype(auto) operator()(Args &&...args) { return fun_(std::ref(*this), std::forward(args)...); } 27 | }; 28 | template decltype(auto) y_combinator(Fun &&fun) { return y_combinator_result>(std::forward(fun)); } 29 | 30 | 31 | template ostream& operator<<(ostream &os, const pair &p) { return os << '(' << p.first << ", " << p.second << ')'; } 32 | template ostream& operator<<(ostream& os, const tuple& t) { os << '('; apply([&os](const Args&... args) { size_t n = 0; ((os << args << (++n != sizeof...(Args) ? ", " : "")), ...); }, t); return os << ')'; } 33 | template::value, typename T_container::value_type>::type> ostream& operator<<(ostream &os, const T_container &v) { os << '{'; string sep; for (const T &x : v) os << sep << x, sep = ", "; return os << '}'; } 34 | 35 | void dbg_out() { cerr << endl; } 36 | template void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); } 37 | #ifdef NEAL_DEBUG 38 | #define dbg(...) cerr << '[' << __FILE__ << ':' << __LINE__ << "] (" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__) 39 | #else 40 | #define dbg(...) 41 | #endif 42 | 43 | // Compresses the values in arr to be in the range [0, n). 44 | template 45 | pair, vector> compress_array(const vector &arr) { 46 | int n = int(arr.size()); 47 | vector> sorted(n); 48 | 49 | for (int i = 0; i < n; i++) 50 | sorted[i] = {arr[i], i}; 51 | 52 | sort(sorted.begin(), sorted.end(), [](const pair &x, const pair &y) -> bool { 53 | return x.first < y.first; 54 | }); 55 | 56 | vector compressed(n); 57 | vector sorted_values; 58 | sorted_values.reserve(n); 59 | int current = 0; 60 | 61 | for (int i = 0, j = 0; i < n; i = j) { 62 | while (j < n && sorted[i].first == sorted[j].first) 63 | compressed[sorted[j++].second] = current; 64 | 65 | sorted_values.push_back(sorted[i].first); 66 | current++; 67 | } 68 | 69 | return {compressed, sorted_values}; 70 | } 71 | 72 | 73 | // Compresses the values in arr to be in the range [0, n). 74 | template 75 | pair, vector> compress_array_binary_search(const vector &arr) { 76 | int n = int(arr.size()); 77 | vector sorted = arr; 78 | sort(sorted.begin(), sorted.end()); 79 | sorted.erase(unique(sorted.begin(), sorted.end()), sorted.end()); 80 | vector compressed(n); 81 | 82 | for (int i = 0; i < n; i++) 83 | compressed[i] = int(lower_bound(sorted.begin(), sorted.end(), arr[i]) - sorted.begin()); 84 | 85 | return {compressed, sorted}; 86 | } 87 | 88 | 89 | uint64_t random_address() { char *p = new char; delete p; return uint64_t(p); } 90 | 91 | const uint64_t SEED = chrono::steady_clock::now().time_since_epoch().count() * (random_address() | 1); 92 | mt19937_64 rng(SEED); 93 | 94 | template 95 | uint64_t compute_hash(const pair, vector> &result) { 96 | uint64_t hash = 0; 97 | 98 | for (const T_out &x : result.first) 99 | hash = 123456789 * hash + x; 100 | 101 | for (const T &x : result.second) 102 | hash = 123456789 * hash + x; 103 | 104 | return hash; 105 | } 106 | 107 | int main(int argc, char **argv) { 108 | ios::sync_with_stdio(false); 109 | #ifndef NEAL_DEBUG 110 | cin.tie(nullptr); 111 | #endif 112 | 113 | cerr << fixed << setprecision(3); 114 | 115 | int N; 116 | int64_t A_MAX; 117 | 118 | if (argc > 2) { 119 | N = stoi(argv[1]); 120 | A_MAX = stoll(argv[2]); 121 | } else { 122 | N = int(1e6); 123 | A_MAX = int64_t(1e10); 124 | } 125 | 126 | vector A(N); 127 | 128 | for (auto &a : A) 129 | a = rng() % A_MAX; 130 | 131 | long double begin; 132 | pair, vector> result; 133 | 134 | begin = clock(); 135 | result = compress_array(A); 136 | cerr << (clock() - begin) / CLOCKS_PER_SEC << 's' << endl; 137 | uint64_t hash0 = compute_hash(result); 138 | cerr << "hash = " << hash0 << endl; 139 | 140 | begin = clock(); 141 | result = compress_array_binary_search(A); 142 | cerr << (clock() - begin) / CLOCKS_PER_SEC << 's' << endl; 143 | uint64_t hash1 = compute_hash(result); 144 | cerr << "hash = " << hash1 << endl; 145 | 146 | assert(hash0 == hash1); 147 | } 148 | -------------------------------------------------------------------------------- /miscellaneous/float_matrix.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // TODO: switch to `double` if `long double` is unnecessary and the time limit is tight. 8 | // Using `long double` is more accurate, but it can be 50-60% slower than `double`. 9 | using matrix_float = long double; 10 | 11 | // TODO: if using float_column_vector, we can write the float_matrix in the format matrix[x] = a row of coefficients 12 | // used to build the x-th element of the float_column_vector. So matrix[0][2] is the coefficient that element 2 13 | // contributes to the next element 0. 14 | // The other option is to take a single-row 1 * n float_matrix and multiply it by the n * n float_matrix. Then 15 | // matrix[0][2] is the coefficient that 0 contributes to the next element 2. 16 | struct float_column_vector { 17 | int rows; 18 | vector values; 19 | 20 | float_column_vector(int _rows = 0) { 21 | init(_rows); 22 | } 23 | 24 | template 25 | float_column_vector(const vector &v) { 26 | init(v); 27 | } 28 | 29 | void init(int _rows) { 30 | rows = _rows; 31 | values.assign(rows, 0); 32 | } 33 | 34 | template 35 | void init(const vector &v) { 36 | rows = int(v.size()); 37 | values = vector(v.begin(), v.end()); 38 | } 39 | 40 | matrix_float& operator[](int index) { return values[index]; } 41 | const matrix_float& operator[](int index) const { return values[index]; } 42 | }; 43 | 44 | // Warning: very inefficient for many small matrices of fixed size. For that, use float_matrix_fixed_size.cc instead. 45 | struct float_matrix { 46 | static float_matrix IDENTITY(int n) { 47 | float_matrix identity(n); 48 | 49 | for (int i = 0; i < n; i++) 50 | identity[i][i] = 1; 51 | 52 | return identity; 53 | } 54 | 55 | int rows, cols; 56 | vector> values; 57 | 58 | float_matrix(int _rows = 0, int _cols = -1) { 59 | init(_rows, _cols); 60 | } 61 | 62 | template 63 | float_matrix(const vector> &v) { 64 | init(v); 65 | } 66 | 67 | void init(int _rows, int _cols = -1) { 68 | rows = _rows; 69 | cols = _cols < 0 ? rows : _cols; 70 | values.assign(rows, vector(cols, 0)); 71 | } 72 | 73 | template 74 | void init(const vector> &v) { 75 | rows = int(v.size()); 76 | cols = v.empty() ? 0 : int(v[0].size()); 77 | values.assign(rows, vector(cols, 0)); 78 | 79 | for (int i = 0; i < rows; i++) { 80 | assert(int(v[i].size()) == cols); 81 | copy(v[i].begin(), v[i].end(), values[i].begin()); 82 | } 83 | } 84 | 85 | vector& operator[](int index) { return values[index]; } 86 | const vector& operator[](int index) const { return values[index]; } 87 | 88 | bool is_square() const { 89 | return rows == cols; 90 | } 91 | 92 | float_matrix operator*(const float_matrix &other) const { 93 | assert(cols == other.rows); 94 | float_matrix product(rows, other.cols); 95 | 96 | for (int i = 0; i < rows; i++) 97 | for (int j = 0; j < cols; j++) 98 | if (values[i][j] != 0) 99 | for (int k = 0; k < other.cols; k++) 100 | product[i][k] += values[i][j] * other[j][k]; 101 | 102 | return product; 103 | } 104 | 105 | float_matrix& operator*=(const float_matrix &other) { 106 | return *this = *this * other; 107 | } 108 | 109 | float_column_vector operator*(const float_column_vector &column) const { 110 | assert(cols == column.rows); 111 | float_column_vector product(rows); 112 | 113 | for (int i = 0; i < rows; i++) 114 | for (int j = 0; j < cols; j++) 115 | product[i] += values[i][j] * column[j]; 116 | 117 | return product; 118 | } 119 | 120 | float_matrix& operator*=(matrix_float mult) { 121 | for (int i = 0; i < rows; i++) 122 | for (int j = 0; j < cols; j++) 123 | values[i][j] *= mult; 124 | 125 | return *this; 126 | } 127 | 128 | float_matrix operator*(matrix_float mult) const { 129 | return float_matrix(*this) *= mult; 130 | } 131 | 132 | float_matrix& operator+=(const float_matrix &other) { 133 | assert(rows == other.rows && cols == other.cols); 134 | 135 | for (int i = 0; i < rows; i++) 136 | for (int j = 0; j < cols; j++) 137 | values[i][j] += other[i][j]; 138 | 139 | return *this; 140 | } 141 | 142 | float_matrix operator+(const float_matrix &other) const { 143 | return float_matrix(*this) += other; 144 | } 145 | 146 | float_matrix& operator-=(const float_matrix &other) { 147 | assert(rows == other.rows && cols == other.cols); 148 | 149 | for (int i = 0; i < rows; i++) 150 | for (int j = 0; j < cols; j++) 151 | values[i][j] -= other[i][j]; 152 | 153 | return *this; 154 | } 155 | 156 | float_matrix operator-(const float_matrix &other) const { 157 | return float_matrix(*this) -= other; 158 | } 159 | 160 | float_matrix pow(int64_t p) const { 161 | assert(p >= 0); 162 | assert(is_square()); 163 | float_matrix m = *this, result = IDENTITY(rows); 164 | 165 | while (p > 0) { 166 | if (p & 1) 167 | result *= m; 168 | 169 | p >>= 1; 170 | 171 | if (p > 0) 172 | m *= m; 173 | } 174 | 175 | return result; 176 | } 177 | 178 | void print(ostream &os) const { 179 | for (int i = 0; i < rows; i++) 180 | for (int j = 0; j < cols; j++) 181 | os << values[i][j] << (j < cols - 1 ? ' ' : '\n'); 182 | 183 | os << '\n'; 184 | } 185 | }; 186 | 187 | 188 | #include 189 | 190 | void read_matrix(float_matrix &m) { 191 | int r, c; 192 | cin >> r >> c; 193 | m = float_matrix(r, c); 194 | 195 | for (int i = 0; i < r; i++) 196 | for (int j = 0; j < c; j++) { 197 | double x; 198 | cin >> x; 199 | m[i][j] = x; 200 | } 201 | } 202 | 203 | int main() { 204 | cout << setprecision(16); 205 | 206 | float_matrix m1, m2; 207 | read_matrix(m1); 208 | read_matrix(m2); 209 | (m1 + m1).print(cout); 210 | (m2 - m2).print(cout); 211 | (m1 * m2).print(cout); 212 | 213 | read_matrix(m1); 214 | int64_t p; 215 | cin >> p; 216 | (m1 * p).print(cout); 217 | m1.pow(p).print(cout); 218 | } 219 | -------------------------------------------------------------------------------- /miscellaneous/floor_div_ceil_div.cc: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int64_t floor_div(int64_t a, int64_t b) { 5 | return a / b - ((a ^ b) < 0 && a % b != 0); 6 | } 7 | 8 | int64_t ceil_div(int64_t a, int64_t b) { 9 | return a / b + ((a ^ b) > 0 && a % b != 0); 10 | } 11 | 12 | 13 | int main() { 14 | int64_t a, b; 15 | 16 | while (cin >> a >> b) 17 | cout << floor_div(a, b) << ' ' << ceil_div(a, b) << '\n'; 18 | } 19 | -------------------------------------------------------------------------------- /miscellaneous/highest_bit.cc: -------------------------------------------------------------------------------- 1 | 2 | int highest_bit(unsigned x) { 3 | return x == 0 ? -1 : 31 - __builtin_clz(x); 4 | } 5 | 6 | 7 | int highest_bit(uint64_t x) { 8 | return x == 0 ? -1 : 63 - __builtin_clzll(x); 9 | } 10 | -------------------------------------------------------------------------------- /miscellaneous/output_vector.cc: -------------------------------------------------------------------------------- 1 | 2 | template 3 | void output_vector(const T_vector &v, int start = 0, int end = -1) { 4 | if (end < 0) end = int(v.size()); 5 | 6 | for (int i = start; i < end; i++) 7 | if constexpr (add_one) 8 | cout << v[i] + 1 << (i < end - 1 ? ' ' : '\n'); 9 | else 10 | cout << v[i] << (i < end - 1 ? ' ' : '\n'); 11 | } 12 | -------------------------------------------------------------------------------- /mod/barrett_int.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | struct barrett_reduction { 9 | unsigned mod; 10 | uint64_t div; 11 | 12 | barrett_reduction(unsigned m) : mod(m), div(-1LLU / m) {} 13 | 14 | unsigned operator()(uint64_t a) const { 15 | #ifdef __SIZEOF_INT128__ 16 | uint64_t q = uint64_t(__uint128_t(div) * a >> 64); 17 | uint64_t r = a - q * mod; 18 | return unsigned(r < mod ? r : r - mod); 19 | #endif 20 | return unsigned(a % mod); 21 | } 22 | }; 23 | 24 | template 25 | struct _b_int { 26 | int val; 27 | 28 | _b_int(int64_t v = 0) { 29 | if (v < 0) v = v % MOD + MOD; 30 | if (v >= MOD) v %= MOD; 31 | val = int(v); 32 | } 33 | 34 | _b_int(uint64_t v) { 35 | if (v >= uint64_t(MOD)) v %= MOD; 36 | val = int(v); 37 | } 38 | 39 | _b_int(int v) : _b_int(int64_t(v)) {} 40 | _b_int(unsigned v) : _b_int(uint64_t(v)) {} 41 | 42 | static int inv_mod(int a, int m = MOD) { 43 | // https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Example 44 | int g = m, r = a, x = 0, y = 1; 45 | 46 | while (r != 0) { 47 | int q = g / r; 48 | g %= r; swap(g, r); 49 | x -= q * y; swap(x, y); 50 | } 51 | 52 | return x < 0 ? x + m : x; 53 | } 54 | 55 | explicit operator int() const { return val; } 56 | explicit operator unsigned() const { return val; } 57 | explicit operator int64_t() const { return val; } 58 | explicit operator uint64_t() const { return val; } 59 | explicit operator double() const { return val; } 60 | explicit operator long double() const { return val; } 61 | 62 | _b_int& operator+=(const _b_int &other) { 63 | val -= MOD - other.val; 64 | if (val < 0) val += MOD; 65 | return *this; 66 | } 67 | 68 | _b_int& operator-=(const _b_int &other) { 69 | val -= other.val; 70 | if (val < 0) val += MOD; 71 | return *this; 72 | } 73 | 74 | static unsigned fast_mod(uint64_t x) { 75 | #if !defined(_WIN32) || defined(_WIN64) 76 | return barrett(x); 77 | #endif 78 | // Optimized mod for Codeforces 32-bit machines. 79 | // x must be less than 2^32 * MOD for this to work, so that x / MOD fits in an unsigned 32-bit int. 80 | unsigned x_high = unsigned(x >> 32), x_low = unsigned(x); 81 | unsigned quot, rem; 82 | asm("divl %4\n" 83 | : "=a" (quot), "=d" (rem) 84 | : "d" (x_high), "a" (x_low), "r" (MOD)); 85 | return rem; 86 | } 87 | 88 | _b_int& operator*=(const _b_int &other) { 89 | val = fast_mod(uint64_t(val) * other.val); 90 | return *this; 91 | } 92 | 93 | _b_int& operator/=(const _b_int &other) { 94 | return *this *= other.inv(); 95 | } 96 | 97 | friend _b_int operator+(const _b_int &a, const _b_int &b) { return _b_int(a) += b; } 98 | friend _b_int operator-(const _b_int &a, const _b_int &b) { return _b_int(a) -= b; } 99 | friend _b_int operator*(const _b_int &a, const _b_int &b) { return _b_int(a) *= b; } 100 | friend _b_int operator/(const _b_int &a, const _b_int &b) { return _b_int(a) /= b; } 101 | 102 | _b_int& operator++() { 103 | val = val == MOD - 1 ? 0 : val + 1; 104 | return *this; 105 | } 106 | 107 | _b_int& operator--() { 108 | val = val == 0 ? MOD - 1 : val - 1; 109 | return *this; 110 | } 111 | 112 | _b_int operator++(int) { _b_int before = *this; ++*this; return before; } 113 | _b_int operator--(int) { _b_int before = *this; --*this; return before; } 114 | 115 | _b_int operator-() const { 116 | return val == 0 ? 0 : MOD - val; 117 | } 118 | 119 | friend bool operator==(const _b_int &a, const _b_int &b) { return a.val == b.val; } 120 | friend bool operator!=(const _b_int &a, const _b_int &b) { return a.val != b.val; } 121 | friend bool operator<(const _b_int &a, const _b_int &b) { return a.val < b.val; } 122 | friend bool operator>(const _b_int &a, const _b_int &b) { return a.val > b.val; } 123 | friend bool operator<=(const _b_int &a, const _b_int &b) { return a.val <= b.val; } 124 | friend bool operator>=(const _b_int &a, const _b_int &b) { return a.val >= b.val; } 125 | 126 | _b_int inv() const { 127 | return inv_mod(val); 128 | } 129 | 130 | _b_int pow(int64_t p) const { 131 | if (p < 0) 132 | return inv().pow(-p); 133 | 134 | _b_int a = *this, result = 1; 135 | 136 | while (p > 0) { 137 | if (p & 1) 138 | result *= a; 139 | 140 | p >>= 1; 141 | 142 | if (p > 0) 143 | a *= a; 144 | } 145 | 146 | return result; 147 | } 148 | 149 | friend ostream& operator<<(ostream &os, const _b_int &m) { 150 | return os << m.val; 151 | } 152 | 153 | friend istream& operator>>(istream &is, _b_int &m) { 154 | int64_t x; 155 | is >> x; 156 | m = x; 157 | return is; 158 | } 159 | }; 160 | 161 | // TODO: double check all pre-initialized values. 162 | // TODO: remember to re-initialize the `barrett` object after reading in `MOD`. 163 | int MOD = int(1e9) + 7; 164 | barrett_reduction barrett(MOD); 165 | using barrett_int = _b_int; 166 | 167 | 168 | #include 169 | #include 170 | 171 | uint64_t random_address() { char *p = new char; delete p; return uint64_t(p); } 172 | mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count() * (random_address() | 1)); 173 | 174 | bool is_prime(int64_t n) { 175 | if (n < 2) 176 | return false; 177 | 178 | for (int64_t p = 2; p * p <= n; p += p % 2 + 1) 179 | if (n % p == 0) 180 | return false; 181 | 182 | return true; 183 | } 184 | 185 | int main() { 186 | int mod; 187 | cin >> mod; 188 | barrett = barrett_reduction(MOD = mod); 189 | 190 | if (is_prime(MOD)) { 191 | for (int iter = 0; iter < 1000; iter++) { 192 | int64_t r = uniform_int_distribution(1, MOD - 1)(rng); 193 | int64_t inv1 = int64_t(barrett_int(r).inv()); 194 | int64_t inv2 = int64_t(barrett_int(r).pow(MOD - 2)); 195 | assert(inv1 == inv2); 196 | assert(r * inv1 % MOD == 1); 197 | } 198 | } 199 | 200 | barrett_int a, b; 201 | cin >> a >> b; 202 | a += b; 203 | cout << a << '\n'; 204 | cin >> a >> b; 205 | a -= b; 206 | cout << a << '\n'; 207 | cin >> a >> b; 208 | a *= b; 209 | cout << a << '\n'; 210 | cin >> a >> b; 211 | if (__gcd(int(b), MOD) % MOD == 1) { 212 | a /= b; 213 | cout << a << '\n'; 214 | } else { 215 | cout << "bad" << '\n'; 216 | } 217 | cin >> a >> b; 218 | cout << a + b << '\n'; 219 | cin >> a >> b; 220 | cout << a - b << '\n'; 221 | cin >> a >> b; 222 | cout << a * b << '\n'; 223 | cin >> a >> b; 224 | if (__gcd(int(b), MOD) % MOD == 1) 225 | cout << a / b << '\n'; 226 | else 227 | cout << "bad" << '\n'; 228 | cin >> a >> b; 229 | cout << -a << ' ' << -b << '\n'; 230 | } 231 | -------------------------------------------------------------------------------- /mod/chinese_remainder_theorem.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | int64_t inv_mod(int64_t a, int64_t m) { 8 | // https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Example 9 | int64_t g = m, r = a, x = 0, y = 1; 10 | 11 | while (r != 0) { 12 | int64_t q = g / r; 13 | g %= r; swap(g, r); 14 | x -= q * y; swap(x, y); 15 | } 16 | 17 | assert(g == 1); 18 | assert(y == m || y == -m); 19 | return x < 0 ? x + m : x; 20 | } 21 | 22 | // Returns a number that is a1 mod m1 and a2 mod m2. Assumes m1 and m2 are relatively prime. 23 | int64_t chinese_remainder_theorem(int64_t a1, int64_t m1, int64_t a2, int64_t m2) { 24 | if (m1 < m2) 25 | return chinese_remainder_theorem(a2, m2, a1, m1); 26 | 27 | // assert(__gcd(m1, m2) == 1); 28 | assert(m1 >= m2); 29 | int64_t k = (a2 - a1) % m2 * inv_mod(m1, m2) % m2; 30 | int64_t result = a1 + k * m1; 31 | 32 | if (result < 0) 33 | result += m1 * m2; 34 | 35 | assert(0 <= result && result < m1 * m2); 36 | assert(result % m1 == a1 && result % m2 == a2); 37 | return result; 38 | } 39 | 40 | template 41 | int64_t chinese_remainder_theorem(const vector &a, const vector &m) { 42 | assert(a.size() == m.size()); 43 | int64_t result = a.front(); 44 | int64_t mod = m.front(); 45 | 46 | for (int i = 1; i < int(m.size()); i++) { 47 | result = chinese_remainder_theorem(result, mod, a[i], m[i]); 48 | mod *= m[i]; 49 | } 50 | 51 | return result; 52 | } 53 | 54 | 55 | #include 56 | #include 57 | 58 | uint64_t random_address() { char *p = new char; delete p; return uint64_t(p); } 59 | mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count() * (random_address() | 1)); 60 | 61 | // Uniformly distributed real number in [a, b). 62 | double real_rng(double a = 0, double b = 1) { 63 | assert(a <= b); 64 | return uniform_real_distribution(a, b)(rng); 65 | } 66 | 67 | // Uniformly distributed integer in [a, b]. 68 | int64_t unif_rng(int64_t a, int64_t b) { 69 | assert(a <= b); 70 | return uniform_int_distribution(a, b)(rng); 71 | } 72 | 73 | // Log-uniform distributed integer in [a, b]. P(a) > P(a + 1) > ... > P(b). 74 | int64_t log_rng(int64_t a, int64_t b) { 75 | assert(a <= b); 76 | double min_val = double(a) - 0.5, max_val = double(b) + 0.5; 77 | int64_t x = int64_t(round(min_val - 1 + exp(real_rng(0, log(max_val - min_val + 1))))); 78 | 79 | // If x - a is large, randomize the lower bits in order to make up for double imprecision. 80 | static const int UNCHANGED_BITS = 30; 81 | 82 | if (uint64_t(x - a) >= 1LLU << UNCHANGED_BITS) 83 | x ^= rng() >> (__builtin_clzll(x - a) + UNCHANGED_BITS); 84 | 85 | return min(max(x, a), b); 86 | } 87 | 88 | // Returns +1 or -1 with 50% probability. 89 | int sign_rng() { 90 | return 2 * int(unif_rng(0, 1)) - 1; 91 | } 92 | 93 | int main() { 94 | const int64_t LIMIT = 9e18; 95 | 96 | for (int64_t test = 1; ; test++) { 97 | int64_t m1, m2; 98 | 99 | do { 100 | m1 = log_rng(1, LIMIT); 101 | m2 = log_rng(1, LIMIT); 102 | } while ((long double) m1 * m2 > LIMIT || __gcd(m1, m2) != 1); 103 | 104 | int64_t a1 = rng() % m1; 105 | int64_t a2 = rng() % m2; 106 | int64_t result = chinese_remainder_theorem(a1, m1, a2, m2); 107 | assert(0 <= result && result < m1 * m2); 108 | assert(result % m1 == a1 && result % m2 == a2); 109 | assert(result == chinese_remainder_theorem(vector{a1, a2}, vector{m1, m2})); 110 | 111 | if (test % 1000000 == 0) 112 | cerr << test << " tests passed!" << endl; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /mod/mod_int.cc: -------------------------------------------------------------------------------- 1 | 2 | template 3 | struct _m_int { 4 | int val; 5 | 6 | _m_int(int64_t v = 0) { 7 | if (v < 0) v = v % MOD + MOD; 8 | if (v >= MOD) v %= MOD; 9 | val = int(v); 10 | } 11 | 12 | _m_int(uint64_t v) { 13 | if (v >= MOD) v %= MOD; 14 | val = int(v); 15 | } 16 | 17 | _m_int(int v) : _m_int(int64_t(v)) {} 18 | _m_int(unsigned v) : _m_int(uint64_t(v)) {} 19 | 20 | explicit operator int() const { return val; } 21 | explicit operator unsigned() const { return val; } 22 | explicit operator int64_t() const { return val; } 23 | explicit operator uint64_t() const { return val; } 24 | explicit operator double() const { return val; } 25 | explicit operator long double() const { return val; } 26 | 27 | _m_int& operator+=(const _m_int &other) { 28 | val -= MOD - other.val; 29 | if (val < 0) val += MOD; 30 | return *this; 31 | } 32 | 33 | _m_int& operator-=(const _m_int &other) { 34 | val -= other.val; 35 | if (val < 0) val += MOD; 36 | return *this; 37 | } 38 | 39 | static unsigned fast_mod(uint64_t x, unsigned m = MOD) { 40 | #if !defined(_WIN32) || defined(_WIN64) 41 | return unsigned(x % m); 42 | #endif 43 | // Optimized mod for Codeforces 32-bit machines. 44 | // x must be less than 2^32 * m for this to work, so that x / m fits in an unsigned 32-bit int. 45 | unsigned x_high = unsigned(x >> 32), x_low = unsigned(x); 46 | unsigned quot, rem; 47 | asm("divl %4\n" 48 | : "=a" (quot), "=d" (rem) 49 | : "d" (x_high), "a" (x_low), "r" (m)); 50 | return rem; 51 | } 52 | 53 | _m_int& operator*=(const _m_int &other) { 54 | val = fast_mod(uint64_t(val) * other.val); 55 | return *this; 56 | } 57 | 58 | _m_int& operator/=(const _m_int &other) { 59 | return *this *= other.inv(); 60 | } 61 | 62 | friend _m_int operator+(const _m_int &a, const _m_int &b) { return _m_int(a) += b; } 63 | friend _m_int operator-(const _m_int &a, const _m_int &b) { return _m_int(a) -= b; } 64 | friend _m_int operator*(const _m_int &a, const _m_int &b) { return _m_int(a) *= b; } 65 | friend _m_int operator/(const _m_int &a, const _m_int &b) { return _m_int(a) /= b; } 66 | 67 | _m_int& operator++() { 68 | val = val == MOD - 1 ? 0 : val + 1; 69 | return *this; 70 | } 71 | 72 | _m_int& operator--() { 73 | val = val == 0 ? MOD - 1 : val - 1; 74 | return *this; 75 | } 76 | 77 | _m_int operator++(int) { _m_int before = *this; ++*this; return before; } 78 | _m_int operator--(int) { _m_int before = *this; --*this; return before; } 79 | 80 | _m_int operator-() const { 81 | return val == 0 ? 0 : MOD - val; 82 | } 83 | 84 | friend bool operator==(const _m_int &a, const _m_int &b) { return a.val == b.val; } 85 | friend bool operator!=(const _m_int &a, const _m_int &b) { return a.val != b.val; } 86 | friend bool operator<(const _m_int &a, const _m_int &b) { return a.val < b.val; } 87 | friend bool operator>(const _m_int &a, const _m_int &b) { return a.val > b.val; } 88 | friend bool operator<=(const _m_int &a, const _m_int &b) { return a.val <= b.val; } 89 | friend bool operator>=(const _m_int &a, const _m_int &b) { return a.val >= b.val; } 90 | 91 | static const int SAVE_INV = int(1e6) + 5; 92 | static _m_int save_inv[SAVE_INV]; 93 | 94 | static void prepare_inv() { 95 | // Ensures that MOD is prime, which is necessary for the inverse algorithm below. 96 | for (int64_t p = 2; p * p <= MOD; p += p % 2 + 1) 97 | assert(MOD % p != 0); 98 | 99 | save_inv[0] = 0; 100 | save_inv[1] = 1; 101 | 102 | for (int i = 2; i < SAVE_INV; i++) 103 | save_inv[i] = save_inv[MOD % i] * (MOD - MOD / i); 104 | } 105 | 106 | _m_int inv() const { 107 | if (save_inv[1] == 0) 108 | prepare_inv(); 109 | 110 | if (val < SAVE_INV) 111 | return save_inv[val]; 112 | 113 | _m_int product = 1; 114 | int v = val; 115 | 116 | do { 117 | product *= MOD - MOD / v; 118 | v = MOD % v; 119 | } while (v >= SAVE_INV); 120 | 121 | return product * save_inv[v]; 122 | } 123 | 124 | _m_int pow(int64_t p) const { 125 | if (p < 0) 126 | return inv().pow(-p); 127 | 128 | _m_int a = *this, result = 1; 129 | 130 | while (p > 0) { 131 | if (p & 1) 132 | result *= a; 133 | 134 | p >>= 1; 135 | 136 | if (p > 0) 137 | a *= a; 138 | } 139 | 140 | return result; 141 | } 142 | 143 | friend ostream& operator<<(ostream &os, const _m_int &m) { 144 | return os << m.val; 145 | } 146 | }; 147 | 148 | template _m_int _m_int::save_inv[_m_int::SAVE_INV]; 149 | 150 | const int MOD = 998244353; 151 | const int MOD = int(1e9) + 7; 152 | using mod_int = _m_int; 153 | -------------------------------------------------------------------------------- /mod/mod_int_simple.cc: -------------------------------------------------------------------------------- 1 | 2 | template 3 | struct _m_int { 4 | int val; 5 | 6 | _m_int(int64_t v = 0) { 7 | if (v < 0) v = v % MOD + MOD; 8 | if (v >= MOD) v %= MOD; 9 | val = int(v); 10 | } 11 | 12 | _m_int(uint64_t v) { 13 | if (v >= MOD) v %= MOD; 14 | val = int(v); 15 | } 16 | 17 | _m_int(int v) : _m_int(int64_t(v)) {} 18 | _m_int(unsigned v) : _m_int(uint64_t(v)) {} 19 | 20 | static int inv_mod(int a, int m = MOD) { 21 | // https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Example 22 | int g = m, r = a, x = 0, y = 1; 23 | 24 | while (r != 0) { 25 | int q = g / r; 26 | g %= r; swap(g, r); 27 | x -= q * y; swap(x, y); 28 | } 29 | 30 | return x < 0 ? x + m : x; 31 | } 32 | 33 | explicit operator int() const { return val; } 34 | explicit operator unsigned() const { return val; } 35 | explicit operator int64_t() const { return val; } 36 | explicit operator uint64_t() const { return val; } 37 | explicit operator double() const { return val; } 38 | explicit operator long double() const { return val; } 39 | 40 | _m_int& operator+=(const _m_int &other) { 41 | val -= MOD - other.val; 42 | if (val < 0) val += MOD; 43 | return *this; 44 | } 45 | 46 | _m_int& operator-=(const _m_int &other) { 47 | val -= other.val; 48 | if (val < 0) val += MOD; 49 | return *this; 50 | } 51 | 52 | static unsigned fast_mod(uint64_t x, unsigned m = MOD) { 53 | #if !defined(_WIN32) || defined(_WIN64) 54 | return unsigned(x % m); 55 | #endif 56 | // Optimized mod for Codeforces 32-bit machines. 57 | // x must be less than 2^32 * m for this to work, so that x / m fits in an unsigned 32-bit int. 58 | unsigned x_high = unsigned(x >> 32), x_low = unsigned(x); 59 | unsigned quot, rem; 60 | asm("divl %4\n" 61 | : "=a" (quot), "=d" (rem) 62 | : "d" (x_high), "a" (x_low), "r" (m)); 63 | return rem; 64 | } 65 | 66 | _m_int& operator*=(const _m_int &other) { 67 | val = fast_mod(uint64_t(val) * other.val); 68 | return *this; 69 | } 70 | 71 | _m_int& operator/=(const _m_int &other) { 72 | return *this *= other.inv(); 73 | } 74 | 75 | friend _m_int operator+(const _m_int &a, const _m_int &b) { return _m_int(a) += b; } 76 | friend _m_int operator-(const _m_int &a, const _m_int &b) { return _m_int(a) -= b; } 77 | friend _m_int operator*(const _m_int &a, const _m_int &b) { return _m_int(a) *= b; } 78 | friend _m_int operator/(const _m_int &a, const _m_int &b) { return _m_int(a) /= b; } 79 | 80 | _m_int& operator++() { 81 | val = val == MOD - 1 ? 0 : val + 1; 82 | return *this; 83 | } 84 | 85 | _m_int& operator--() { 86 | val = val == 0 ? MOD - 1 : val - 1; 87 | return *this; 88 | } 89 | 90 | _m_int operator++(int) { _m_int before = *this; ++*this; return before; } 91 | _m_int operator--(int) { _m_int before = *this; --*this; return before; } 92 | 93 | _m_int operator-() const { 94 | return val == 0 ? 0 : MOD - val; 95 | } 96 | 97 | friend bool operator==(const _m_int &a, const _m_int &b) { return a.val == b.val; } 98 | friend bool operator!=(const _m_int &a, const _m_int &b) { return a.val != b.val; } 99 | friend bool operator<(const _m_int &a, const _m_int &b) { return a.val < b.val; } 100 | friend bool operator>(const _m_int &a, const _m_int &b) { return a.val > b.val; } 101 | friend bool operator<=(const _m_int &a, const _m_int &b) { return a.val <= b.val; } 102 | friend bool operator>=(const _m_int &a, const _m_int &b) { return a.val >= b.val; } 103 | 104 | _m_int inv() const { 105 | return inv_mod(val); 106 | } 107 | 108 | _m_int pow(int64_t p) const { 109 | if (p < 0) 110 | return inv().pow(-p); 111 | 112 | _m_int a = *this, result = 1; 113 | 114 | while (p > 0) { 115 | if (p & 1) 116 | result *= a; 117 | 118 | p >>= 1; 119 | 120 | if (p > 0) 121 | a *= a; 122 | } 123 | 124 | return result; 125 | } 126 | 127 | friend ostream& operator<<(ostream &os, const _m_int &m) { 128 | return os << m.val; 129 | } 130 | }; 131 | 132 | const int MOD = 998244353; 133 | const int MOD = int(1e9) + 7; 134 | using mod_int = _m_int; 135 | -------------------------------------------------------------------------------- /number_theory/fraction.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | struct fraction { 10 | // TODO: set this to false if it's unnecessary and the time limit might be tight. 11 | // CHECK_OVERFLOW64 = true can run up to 2 times slower (particularly on CF). 12 | static const bool CHECK_OVERFLOW64 = true; 13 | 14 | // TODO: consider setting AUTO_REDUCE = false for faster code. In this case, remember to call reduce() at the end. 15 | static const bool AUTO_REDUCE = true; 16 | 17 | static int cross_sign(const fraction &a, const fraction &b) { 18 | if (CHECK_OVERFLOW64) { 19 | long double double_value = (long double) a.numer * b.denom - (long double) b.numer * a.denom; 20 | 21 | if (abs(double_value) > 1e18) 22 | return (double_value > 0) - (double_value < 0); 23 | } 24 | 25 | uint64_t uint64_value = (uint64_t) a.numer * b.denom - (uint64_t) b.numer * a.denom; 26 | int64_t actual = int64_t(uint64_value); 27 | return (actual > 0) - (actual < 0); 28 | } 29 | 30 | int64_t numer, denom; 31 | 32 | fraction(int64_t n = 0, int64_t d = 1) : numer(n), denom(d) { 33 | check_denom(); 34 | 35 | if (AUTO_REDUCE) 36 | reduce(); 37 | } 38 | 39 | void check_denom() { 40 | if (denom < 0) { 41 | numer = -numer; 42 | denom = -denom; 43 | } 44 | } 45 | 46 | void reduce() { 47 | int64_t g = __gcd(abs(numer), denom); 48 | numer /= g; 49 | denom /= g; 50 | } 51 | 52 | bool is_integer() const { 53 | return denom == 1 || (!AUTO_REDUCE && denom != 0 && numer % denom == 0); 54 | } 55 | 56 | friend fraction operator+(const fraction &a, const fraction &b) { 57 | return fraction(a.numer * b.denom + b.numer * a.denom, a.denom * b.denom); 58 | } 59 | 60 | friend fraction operator-(const fraction &a, const fraction &b) { 61 | return fraction(a.numer * b.denom - b.numer * a.denom, a.denom * b.denom); 62 | } 63 | 64 | friend fraction operator*(const fraction &a, const fraction &b) { 65 | return fraction(a.numer * b.numer, a.denom * b.denom); 66 | } 67 | 68 | friend fraction operator/(const fraction &a, const fraction &b) { 69 | return fraction(a.numer * b.denom, a.denom * b.numer); 70 | } 71 | 72 | fraction& operator+=(const fraction &other) { return *this = *this + other; } 73 | fraction& operator-=(const fraction &other) { return *this = *this - other; } 74 | fraction& operator*=(const fraction &other) { return *this = *this * other; } 75 | fraction& operator/=(const fraction &other) { return *this = *this / other; } 76 | 77 | fraction& operator++() { numer += denom; return *this; } 78 | fraction& operator--() { numer -= denom; return *this; } 79 | 80 | fraction operator++(int) { fraction before = *this; ++*this; return before; } 81 | fraction operator--(int) { fraction before = *this; --*this; return before; } 82 | 83 | fraction operator-() const { 84 | return fraction(-numer, denom); 85 | } 86 | 87 | fraction inv() const { 88 | return fraction(denom, numer); 89 | } 90 | 91 | bool operator==(const fraction &other) const { return cross_sign(*this, other) == 0; } 92 | bool operator!=(const fraction &other) const { return cross_sign(*this, other) != 0; } 93 | bool operator<(const fraction &other) const { return cross_sign(*this, other) < 0; } 94 | bool operator>(const fraction &other) const { return cross_sign(*this, other) > 0; } 95 | bool operator<=(const fraction &other) const { return cross_sign(*this, other) <= 0; } 96 | bool operator>=(const fraction &other) const { return cross_sign(*this, other) >= 0; } 97 | 98 | explicit operator double() const { 99 | return double(numer) / double(denom); 100 | } 101 | 102 | explicit operator long double() const { 103 | return (long double) numer / (long double) denom; 104 | } 105 | 106 | friend fraction abs(const fraction &f) { 107 | return fraction(abs(f.numer), f.denom); 108 | } 109 | 110 | friend ostream& operator<<(ostream& out, const fraction &frac) { 111 | return out << frac.numer << '/' << frac.denom; 112 | } 113 | }; 114 | 115 | 116 | int main() { 117 | cout << setprecision(12); 118 | 119 | int64_t A, B, C, D; 120 | cin >> A >> B >> C >> D; 121 | fraction x(A, B), y(C, D); 122 | cout << min(x, y) << '\n'; 123 | cout << max(x, y) << '\n'; 124 | cout << x + y << '\n'; 125 | cout << x - y << '\n'; 126 | cout << x * y << '\n'; 127 | cout << x / y << '\n'; 128 | x++; 129 | y--; 130 | cout << x << '\n'; 131 | cout << y << '\n'; 132 | cout << abs(x) << '\n'; 133 | cout << abs(y) << '\n'; 134 | cout << double(x) << '\n'; 135 | cout << (long double) y << '\n'; 136 | } 137 | -------------------------------------------------------------------------------- /number_theory/miller_rabin.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | uint64_t mod_mul64(uint64_t a, uint64_t b, uint64_t mod) { 9 | assert(a < mod && b < mod); 10 | 11 | if (mod <= 1LLU << 32) 12 | return a * b % mod; 13 | 14 | if (mod <= 1LLU << 63) { 15 | uint64_t q = uint64_t((long double) a * b / mod); 16 | uint64_t result = a * b - q * mod; 17 | 18 | if (result > 1LLU << 63) 19 | result += mod; 20 | else if (result >= mod) 21 | result -= mod; 22 | 23 | return result; 24 | } 25 | 26 | #ifdef __SIZEOF_INT128__ 27 | return uint64_t(__uint128_t(a) * b % mod); 28 | #endif 29 | 30 | assert(false); 31 | } 32 | 33 | uint64_t mod_pow64(uint64_t a, uint64_t b, uint64_t mod) { 34 | uint64_t result = 1; 35 | 36 | while (b > 0) { 37 | if (b & 1) 38 | result = mod_mul64(result, a, mod); 39 | 40 | a = mod_mul64(a, a, mod); 41 | b >>= 1; 42 | } 43 | 44 | return result; 45 | } 46 | 47 | bool miller_rabin(uint64_t n) { 48 | if (n < 2) 49 | return false; 50 | 51 | // Check small primes. 52 | for (uint64_t p : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29}) 53 | if (n % p == 0) 54 | return n == p; 55 | 56 | // https://miller-rabin.appspot.com/ 57 | auto get_miller_rabin_bases = [&]() -> vector { 58 | if (n < 341531) return {9345883071009581737LLU}; 59 | if (n < 1050535501) return {336781006125, 9639812373923155}; 60 | if (n < 350269456337) return {4230279247111683200, 14694767155120705706LLU, 16641139526367750375LLU}; 61 | if (n < 55245642489451) return {2, 141889084524735, 1199124725622454117, 11096072698276303650LLU}; 62 | if (n < 7999252175582851) return {2, 4130806001517, 149795463772692060, 186635894390467037, 3967304179347715805}; 63 | if (n < 585226005592931977) return {2, 123635709730000, 9233062284813009, 43835965440333360, 761179012939631437, 1263739024124850375}; 64 | return {2, 325, 9375, 28178, 450775, 9780504, 1795265022}; 65 | }; 66 | 67 | int r = __builtin_ctzll(n - 1); 68 | uint64_t d = (n - 1) >> r; 69 | 70 | for (uint64_t a : get_miller_rabin_bases()) { 71 | if (a % n == 0) 72 | continue; 73 | 74 | uint64_t x = mod_pow64(a % n, d, n); 75 | 76 | if (x == 1 || x == n - 1) 77 | continue; 78 | 79 | for (int i = 0; i < r - 1 && x != n - 1; i++) 80 | x = mod_mul64(x, x, n); 81 | 82 | if (x != n - 1) 83 | return false; 84 | } 85 | 86 | return true; 87 | } 88 | 89 | // Solution to https://www.spoj.com/problems/PON/ 90 | int main() { 91 | ios::sync_with_stdio(false); 92 | #ifndef NEAL_DEBUG 93 | cin.tie(nullptr); 94 | #endif 95 | 96 | uint64_t n; 97 | cin >> n; 98 | 99 | while (cin >> n) 100 | // cout << (miller_rabin(n) ? "YES" : "NO") << '\n'; 101 | cout << n << ": " << (miller_rabin(n) ? "YES" : "NO") << '\n'; 102 | } 103 | -------------------------------------------------------------------------------- /number_theory/sieve_linear.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | vector smallest_factor; 8 | vector prime; 9 | vector primes; 10 | 11 | // Note: this sieve is O(n), but the constant factor is worse than the O(n log log n) sieve due to the multiplication. 12 | void sieve(int maximum) { 13 | maximum = max(maximum, 1); 14 | smallest_factor.assign(maximum + 1, 0); 15 | prime.assign(maximum + 1, true); 16 | prime[0] = prime[1] = false; 17 | primes = {}; 18 | 19 | for (int i = 2; i <= maximum; i++) { 20 | if (prime[i]) { 21 | smallest_factor[i] = i; 22 | primes.push_back(i); 23 | } 24 | 25 | for (int p : primes) { 26 | if (p > smallest_factor[i] || int64_t(i) * p > maximum) 27 | break; 28 | 29 | prime[i * p] = false; 30 | smallest_factor[i * p] = p; 31 | } 32 | } 33 | } 34 | 35 | 36 | #include 37 | 38 | int main() { 39 | int n; 40 | scanf("%d", &n); 41 | sieve(n); 42 | printf("%lld = sum of primes\n", accumulate(primes.begin(), primes.end(), 0LL)); 43 | printf("%d = number of primes\n", accumulate(prime.begin(), prime.end(), 0)); 44 | printf("%lld = sum of smallest_factor\n", accumulate(smallest_factor.begin(), smallest_factor.end(), 0LL)); 45 | } 46 | -------------------------------------------------------------------------------- /rmq_lca/cartesian_tree_parent_only.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // Use compare = less() for a min heap and compare = greater() for a max heap. 9 | // When there are ties, the left value will be the parent of the right value. 10 | template 11 | vector build_cartesian_tree(const vector &A, Compare &&compare) { 12 | int n = int(A.size()); 13 | vector parent(n, -1); 14 | vector stack; 15 | 16 | for (int i = 0; i < n; i++) { 17 | int erased = -1; 18 | 19 | while (!stack.empty() && compare(A[i], A[stack.back()])) { 20 | erased = stack.back(); 21 | stack.pop_back(); 22 | } 23 | 24 | parent[i] = stack.empty() ? -1 : stack.back(); 25 | 26 | if (erased >= 0) 27 | parent[erased] = i; 28 | 29 | stack.push_back(i); 30 | } 31 | 32 | return parent; 33 | } 34 | 35 | int main() { 36 | ios::sync_with_stdio(false); 37 | #ifndef NEAL_DEBUG 38 | cin.tie(nullptr); 39 | #endif 40 | 41 | int N; 42 | cin >> N; 43 | vector A(N); 44 | 45 | for (auto &a : A) 46 | cin >> a; 47 | 48 | vector parent = build_cartesian_tree(A, less()); 49 | 50 | for (int i = 0; i < N; i++) 51 | cout << parent[i] + 1 << (i < N - 1 ? ' ' : '\n'); 52 | 53 | parent = build_cartesian_tree(A, greater()); 54 | 55 | for (int i = 0; i < N; i++) 56 | cout << parent[i] + 1 << (i < N - 1 ? ' ' : '\n'); 57 | } 58 | -------------------------------------------------------------------------------- /rmq_lca/monotonic_rmq_deque.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | const int INF = int(1e9) + 5; 10 | 11 | template 12 | struct monotonic_RMQ { 13 | deque> values; 14 | int current_index = 0; 15 | 16 | static bool is_better(T a, T b) { 17 | return maximum_mode ? b < a : a < b; 18 | } 19 | 20 | int prev_add_index = -INF, prev_query_index = -INF; 21 | 22 | // Adds a value and returns its index. 23 | int add(const T &x, int index = -INF) { 24 | if (index == -INF) 25 | index = current_index++; 26 | 27 | assert(index >= prev_add_index); 28 | prev_add_index = index; 29 | 30 | while (!values.empty() && !is_better(values.back().first, x)) 31 | values.pop_back(); 32 | 33 | values.emplace_back(x, index); 34 | return index; 35 | } 36 | 37 | // Queries for the maximum (minimum) with index at least the given `index`. `index` must be non-decreasing. 38 | // TODO: when calling query, make sure to handle the empty case. 39 | T query_index(int index) { 40 | assert(index >= prev_query_index); 41 | prev_query_index = index; 42 | 43 | while (!values.empty() && values.front().second < index) 44 | values.pop_front(); 45 | 46 | if (values.empty()) 47 | return maximum_mode ? (is_signed::value ? -T_INF : 0) : T_INF; 48 | 49 | return values.front().first; 50 | } 51 | 52 | // Warning: does not work when adding with custom indices. 53 | T query_count(int count) { 54 | return query_index(current_index - count); 55 | } 56 | 57 | // Returns whether or not the queue has a result for querying the given index. 58 | bool has_index(int index) const { 59 | return !values.empty() && values.back().second >= index; 60 | } 61 | 62 | bool has_count(int count) const { 63 | return has_index(current_index - count); 64 | } 65 | }; 66 | 67 | 68 | template 69 | vector rmq_every_k(const vector &values, int k) { 70 | int n = int(values.size()); 71 | assert(1 <= k && k <= n); 72 | monotonic_RMQ::max()> rmq; 73 | vector result(n - k + 1); 74 | 75 | for (int i = 0; i < n; i++) { 76 | rmq.add(values[i]); 77 | assert(rmq.has_index(i) && !rmq.has_index(i + 1)); 78 | 79 | if (i >= k - 1) { 80 | assert(rmq.has_count(k)); 81 | result[i - (k - 1)] = rmq.query_count(k); 82 | } 83 | } 84 | 85 | return result; 86 | } 87 | 88 | 89 | int main() { 90 | ios::sync_with_stdio(false); 91 | #ifndef NEAL_DEBUG 92 | cin.tie(nullptr); 93 | #endif 94 | 95 | int N, K; 96 | cin >> N >> K; 97 | vector values(N); 98 | 99 | for (int64_t &val : values) 100 | cin >> val; 101 | 102 | vector min_result = rmq_every_k(values, K); 103 | vector max_result = rmq_every_k(values, K); 104 | 105 | for (int i = 0; i < int(min_result.size()); i++) 106 | cout << min_result[i] << ' ' << max_result[i] << '\n'; 107 | } 108 | -------------------------------------------------------------------------------- /scc_two_sat/scc_two_sat.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct SCC { 8 | int V = 0; 9 | vector> adj; 10 | vector tour_index, low_link; 11 | int tour; 12 | 13 | vector stack; 14 | vector in_stack; 15 | 16 | vector> components; 17 | vector which_component; 18 | 19 | SCC(int v = 0) { 20 | init(v); 21 | } 22 | 23 | SCC(const vector> &_adj) { 24 | init(_adj); 25 | } 26 | 27 | void init(int v) { 28 | V = v; 29 | adj.assign(V, {}); 30 | } 31 | 32 | void init(const vector> &_adj) { 33 | adj = _adj; 34 | V = int(adj.size()); 35 | } 36 | 37 | void add_edge(int a, int b) { 38 | adj[a].push_back(b); 39 | } 40 | 41 | // Tarjan's algorithm. 42 | void dfs(int node) { 43 | tour_index[node] = tour++; 44 | low_link[node] = tour_index[node]; 45 | stack.push_back(node); 46 | in_stack[node] = true; 47 | 48 | for (int neighbor : adj[node]) 49 | if (tour_index[neighbor] < 0) { 50 | // neighbor is part of our subtree. 51 | dfs(neighbor); 52 | low_link[node] = min(low_link[node], low_link[neighbor]); 53 | } else if (in_stack[neighbor]) { 54 | // neighbor is a candidate for low_link. 55 | low_link[node] = min(low_link[node], tour_index[neighbor]); 56 | } 57 | 58 | if (low_link[node] == tour_index[node]) { 59 | // node is the highest node in an SCC, which includes everything on the stack up to it. 60 | components.emplace_back(); 61 | vector &component = components.back(); 62 | int x; 63 | 64 | do { 65 | assert(!stack.empty()); 66 | x = stack.back(); 67 | stack.pop_back(); 68 | in_stack[x] = false; 69 | which_component[x] = int(components.size()) - 1; 70 | component.push_back(x); 71 | } while (x != node); 72 | } 73 | } 74 | 75 | void build() { 76 | tour_index.assign(V, -1); 77 | low_link.resize(V); 78 | which_component.assign(V, -1); 79 | 80 | stack.clear(); 81 | stack.reserve(V); 82 | in_stack.assign(V, false); 83 | tour = 0; 84 | 85 | // Note that Tarjan's algorithm provides the SCCs in reverse topological order. 86 | components = {}; 87 | 88 | for (int i = 0; i < V; i++) 89 | if (tour_index[i] < 0) 90 | dfs(i); 91 | } 92 | }; 93 | 94 | 95 | struct two_sat { 96 | int n = 0; 97 | vector> adj; 98 | vector assignment; 99 | SCC scc; 100 | 101 | two_sat(int _n = 0) { 102 | init(_n); 103 | } 104 | 105 | void init(int _n) { 106 | n = _n; 107 | adj.assign(2 * n, {}); 108 | } 109 | 110 | int inv(int var) { 111 | return var ^ 1; 112 | } 113 | 114 | int new_var() { 115 | adj.emplace_back(); 116 | adj.emplace_back(); 117 | return 2 * n++; 118 | } 119 | 120 | void implies(int a, int b) { 121 | adj[a].push_back(b); 122 | adj[inv(b)].push_back(inv(a)); 123 | } 124 | 125 | void either(int a, int b) { 126 | adj[inv(a)].push_back(b); 127 | adj[inv(b)].push_back(a); 128 | } 129 | 130 | void set_value(int a) { 131 | adj[inv(a)].push_back(a); 132 | } 133 | 134 | void equal(int a, int b) { 135 | implies(a, b); 136 | implies(inv(a), inv(b)); 137 | } 138 | 139 | void unequal(int a, int b) { 140 | implies(a, inv(b)); 141 | implies(inv(a), b); 142 | } 143 | 144 | // Warning: this only creates an implication in the negative direction. It is still possible for 145 | // a = b = true with and_var = false. In particular, it does not work to call set_value on inv(and_var). 146 | int create_and(int a, int b) { 147 | if (a < 0 || b < 0) return max(a, b); 148 | int result = new_var(); 149 | implies(result, a); 150 | implies(result, b); 151 | return result; 152 | } 153 | 154 | // Warning: this only creates an implication in the positive direction. It is still possible for 155 | // a = b = false with or_var = true. In particular, it does not work to call set_value on or_var. 156 | int create_or(int a, int b) { 157 | if (a < 0 || b < 0) return max(a, b); 158 | int result = new_var(); 159 | implies(a, result); 160 | implies(b, result); 161 | return result; 162 | } 163 | 164 | int create_at_most_one(int a, int b) { 165 | if (a < 0 || b < 0) return max(a, b); 166 | either(inv(a), inv(b)); 167 | return create_or(a, b); 168 | } 169 | 170 | template 171 | int create_at_most_one(const T_iterable &vars) { 172 | int aux = -1; 173 | 174 | for (int var : vars) 175 | aux = create_at_most_one(aux, var); 176 | 177 | return aux; 178 | } 179 | 180 | bool solve() { 181 | scc.init(adj); 182 | scc.build(); 183 | 184 | for (int i = 0; i < n; i++) 185 | if (scc.which_component[2 * i] == scc.which_component[2 * i + 1]) 186 | return false; 187 | 188 | assignment.resize(2 * n); 189 | vector done(n, false); 190 | 191 | // Tarjan's algorithm provides the SCCs in reverse topological order. 192 | for (auto &component : scc.components) 193 | for (int x : component) { 194 | assignment[x] = !done[x / 2]; 195 | done[x / 2] = true; 196 | } 197 | 198 | for (int i = 0; i < n; i++) 199 | assert(assignment[2 * i] ^ assignment[2 * i + 1]); 200 | 201 | return true; 202 | } 203 | }; 204 | 205 | 206 | int main() { 207 | 208 | } 209 | -------------------------------------------------------------------------------- /seg_tree/fenwick_tree.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | template 9 | struct fenwick_tree { 10 | static int highest_bit(unsigned x) { 11 | return x == 0 ? -1 : 31 - __builtin_clz(x); 12 | } 13 | 14 | int tree_n = 0; 15 | T tree_sum = T(); 16 | vector tree; 17 | 18 | fenwick_tree(int n = -1) { 19 | if (n >= 0) 20 | init(n); 21 | } 22 | 23 | void init(int n) { 24 | tree_n = n; 25 | tree_sum = T(); 26 | tree.assign(tree_n + 1, T()); 27 | } 28 | 29 | // O(n) initialization of the Fenwick tree. 30 | template 31 | void build(const T_array &initial) { 32 | assert(int(initial.size()) == tree_n); 33 | tree_sum = T(); 34 | 35 | for (int i = 1; i <= tree_n; i++) { 36 | tree[i] = initial[i - 1]; 37 | tree_sum += initial[i - 1]; 38 | 39 | for (int k = (i & -i) >> 1; k > 0; k >>= 1) 40 | tree[i] += tree[i - k]; 41 | } 42 | } 43 | 44 | // index is in [0, tree_n). 45 | void update(int index, const T &change) { 46 | assert(0 <= index && index < tree_n); 47 | tree_sum += change; 48 | 49 | for (int i = index + 1; i <= tree_n; i += i & -i) 50 | tree[i] += change; 51 | } 52 | 53 | // Returns the sum of the range [0, count). 54 | T query(int count) const { 55 | count = min(count, tree_n); 56 | T sum = T(); 57 | 58 | for (int i = count; i > 0; i -= i & -i) 59 | sum += tree[i]; 60 | 61 | return sum; 62 | } 63 | 64 | // Returns the sum of the range [start, tree_n). 65 | T query_suffix(int start) const { 66 | return tree_sum - query(start); 67 | } 68 | 69 | // Returns the sum of the range [a, b). 70 | T query(int a, int b) const { 71 | return query(b) - query(a); 72 | } 73 | 74 | // Returns the element at index a in O(1) amortized across every index. Equivalent to query(a, a + 1). 75 | T get(int a) const { 76 | assert(0 <= a && a < tree_n); 77 | int above = a + 1; 78 | T sum = tree[above]; 79 | above -= above & -above; 80 | 81 | while (a != above) { 82 | sum -= tree[a]; 83 | a -= a & -a; 84 | } 85 | 86 | return sum; 87 | } 88 | 89 | bool set(int index, T value) { 90 | assert(0 <= index && index < tree_n); 91 | T current = get(index); 92 | 93 | if (current == value) 94 | return false; 95 | 96 | update(index, value - current); 97 | return true; 98 | } 99 | 100 | // Returns the largest p in `[0, tree_n]` such that `query(p) <= sum`. Returns -1 if no such p exists (`sum < 0`). 101 | // Can be used as an ordered set/multiset on indices in `[0, tree_n)` by using the tree as a 0/1 or frequency array: 102 | // `set(index, 1)` is equivalent to insert(index). `update(index, +1)` is equivalent to multiset.insert(index). 103 | // `set(index, 0)` or `update(index, -1)` are equivalent to erase(index). 104 | // `get(index)` provides whether index is present or not, or the count of index (if multiset). 105 | // `query(index)` provides the count of elements < index. 106 | // `find_last_prefix(k)` finds the k-th smallest element (0-indexed). Returns `tree_n` for `sum >= set.size()`. 107 | int find_last_prefix(T sum) const { 108 | if (sum < T()) 109 | return -1; 110 | 111 | int prefix = 0; 112 | 113 | for (int k = highest_bit(tree_n); k >= 0; k--) 114 | if (prefix + (1 << k) <= tree_n && tree[prefix + (1 << k)] <= sum) { 115 | prefix += 1 << k; 116 | sum -= tree[prefix]; 117 | } 118 | 119 | return prefix; 120 | } 121 | }; 122 | 123 | 124 | int main() { 125 | ios::sync_with_stdio(false); 126 | #ifndef NEAL_DEBUG 127 | cin.tie(nullptr); 128 | #endif 129 | 130 | int N, Q; 131 | cin >> N >> Q; 132 | fenwick_tree tree(N); 133 | 134 | for (int q = 0; q < Q; q++) { 135 | // This can handle the following operations (described below with inclusive 1-based indexing): 136 | // 1) "add a b x": add x to numbers[a] through numbers[b]. Must have a = b. 137 | // 2) "set a b x": set all of numbers[a] through numbers[b] to x. Must have a = b. 138 | // 4) "sum a b": compute the sum of numbers[a] through numbers[b]. 139 | // 7) "fsum a x": given a, find the first index i with a - 1 <= i <= N such that numbers[a] + ... + numbers[i] 140 | // is >= x (sum = 0 when i = a - 1). If no such i exists, print -1. 141 | string type; 142 | int a, b; 143 | int64_t x; 144 | cin >> type; 145 | 146 | if (type == "fsum") { 147 | cin >> a >> x; 148 | a--; 149 | int index = tree.find_last_prefix(tree.query(a) + x - 1); 150 | index = max(index, a - 1); 151 | cout << (index < N ? index + 1 : -1) << '\n'; 152 | continue; 153 | } 154 | 155 | cin >> a >> b; 156 | a--; 157 | assert(0 <= a && a < b && b <= N); 158 | 159 | if (type == "add" || type == "set") 160 | cin >> x; 161 | 162 | if (type == "add") { 163 | assert(b - a == 1); 164 | tree.update(a, x); 165 | } else if (type == "set") { 166 | assert(b - a == 1); 167 | tree.set(a, x); 168 | } else if (type == "sum") { 169 | if (b == N && q % 2 == 0) { 170 | cout << tree.query_suffix(a) << '\n'; 171 | continue; 172 | } 173 | 174 | cout << tree.query(a, b) << '\n'; 175 | } else { 176 | assert(false); 177 | } 178 | } 179 | 180 | for (int i = 0; i < N; i++) 181 | cout << tree.get(i) << (i < N - 1 ? ' ' : '\n'); 182 | } 183 | -------------------------------------------------------------------------------- /seg_tree/persistent_array.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // A persistent array that uses log n time per lookup, as well as log n time and log n memory per update. 9 | // TODO: persistent trees have both bad constant factor and high memory usage. Make sure we won't TLE or MLE. 10 | template 11 | struct persistent_array { 12 | int tree_n = 0; 13 | vector> tree; 14 | vector values; 15 | int tree_reserve_size = INT32_MAX, value_reserve_size = INT32_MAX; 16 | 17 | persistent_array(int n = -1, int max_updates = 0) { 18 | if (n >= 0) 19 | init(n, max_updates); 20 | } 21 | 22 | persistent_array(const vector &v, int max_updates = 0) { 23 | init(v, max_updates); 24 | } 25 | 26 | void init(int n, int max_updates = 0) { 27 | init(vector(n, T()), max_updates); 28 | } 29 | 30 | // Directly assigning `tree[position] = f(...)` results in segmentation faults, because the address for 31 | // `tree[position]` can be computed before calling `f()`, which may reallocate `tree`. 32 | void _set_children(int position, int left, int right) { tree[position] = {left, right}; } 33 | void _set_left(int position, int left) { tree[position][0] = left; } 34 | void _set_right(int position, int right) { tree[position][1] = right; } 35 | 36 | int _build_tree(int start, int end) { 37 | if (start >= end) 38 | return -1; 39 | 40 | int node = int(tree.size()); 41 | tree.emplace_back(); 42 | 43 | // At leaves, we set `tree[node]` to point to the appropriate index in `values`. 44 | if (end - start == 1) { 45 | _set_children(node, start, start); 46 | return node; 47 | } 48 | 49 | int mid = (start + end) / 2; 50 | _set_children(node, _build_tree(start, mid), _build_tree(mid, end)); 51 | return node; 52 | } 53 | 54 | void init(const vector &v, int max_updates = 0) { 55 | tree_n = int(v.size()); 56 | values = v; 57 | tree = {{-1, -1}}; 58 | tree_reserve_size = value_reserve_size = INT32_MAX; 59 | 60 | if (max_updates > 0) { 61 | // We need to add one to tree_height if tree_n is not a power of two. 62 | int tree_height = 32 - __builtin_clz(tree_n) + ((tree_n & (tree_n - 1)) != 0); 63 | tree_reserve_size = 2 * tree_n + max_updates * tree_height; 64 | value_reserve_size = tree_n + max_updates; 65 | tree.reserve(tree_reserve_size); 66 | values.reserve(value_reserve_size); 67 | } 68 | 69 | _build_tree(0, tree_n); 70 | } 71 | 72 | T get(int root, int index) const { 73 | assert(root > 0 && 0 <= index && index < tree_n); 74 | int current = root; 75 | int start = 0, end = tree_n; 76 | 77 | while (end - start > 1) { 78 | int mid = (start + end) / 2; 79 | 80 | if (index < mid) { 81 | current = tree[current][0]; 82 | end = mid; 83 | } else { 84 | current = tree[current][1]; 85 | start = mid; 86 | } 87 | } 88 | 89 | assert(start == index && end == index + 1); 90 | return values[tree[current][0]]; 91 | } 92 | 93 | int _make_copy(int position) { 94 | assert(0 <= position && position < int(tree.size())); 95 | tree.push_back(tree[position]); 96 | assert(int(tree.size()) <= tree_reserve_size); 97 | return int(tree.size()) - 1; 98 | } 99 | 100 | int _update_tree(int position, int start, int end, int index, T value) { 101 | assert(start < end); 102 | position = _make_copy(position); 103 | 104 | if (end - start == 1) { 105 | assert(start == index); 106 | _set_children(position, int(values.size()), int(values.size())); 107 | values.push_back(value); 108 | assert(int(values.size()) <= value_reserve_size); 109 | return position; 110 | } 111 | 112 | int mid = (start + end) / 2; 113 | 114 | if (index < mid) 115 | _set_left(position, _update_tree(tree[position][0], start, mid, index, value)); 116 | else 117 | _set_right(position, _update_tree(tree[position][1], mid, end, index, value)); 118 | 119 | return position; 120 | } 121 | 122 | int update(int root, int index, T value) { 123 | assert(root > 0 && 0 <= index && index < tree_n); 124 | return _update_tree(root, 0, tree_n, index, value); 125 | } 126 | }; 127 | 128 | 129 | int main() { 130 | ios::sync_with_stdio(false); 131 | #ifndef NEAL_DEBUG 132 | cin.tie(nullptr); 133 | #endif 134 | 135 | int N, Q; 136 | cin >> N >> Q; 137 | persistent_array values(N, Q); 138 | vector roots(Q + 1, 1); 139 | 140 | for (int q = 1; q <= Q; q++) { 141 | string type; 142 | int index, value; 143 | cin >> type >> index; 144 | 145 | if (type == "load") { 146 | roots[q] = roots[index]; 147 | } else if (type == "set") { 148 | index--; 149 | cin >> value; 150 | roots[q] = values.update(roots[q - 1], index, value); 151 | } else if (type == "query") { 152 | index--; 153 | roots[q] = roots[q - 1]; 154 | cout << values.get(roots[q], index) << '\n'; 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /shortest_path/bfs.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | const int INF = int(1e9) + 5; 10 | 11 | struct BFS { 12 | struct edge { 13 | int node = -1, weight = -1; 14 | 15 | edge() {} 16 | 17 | edge(int _node, int _weight) : node(_node), weight(_weight) {} 18 | }; 19 | 20 | int n; 21 | vector> adj; 22 | vector dist; 23 | vector parent; 24 | 25 | BFS(int _n = 0) { 26 | init(_n); 27 | } 28 | 29 | void init(int _n) { 30 | n = _n; 31 | adj.assign(n, {}); 32 | } 33 | 34 | void add_directional_edge(int a, int b, int weight) { 35 | assert(0 <= weight && weight <= 1); 36 | adj[a].emplace_back(b, weight); 37 | } 38 | 39 | void add_bidirectional_edge(int a, int b, int weight) { 40 | assert(0 <= weight && weight <= 1); 41 | adj[a].emplace_back(b, weight); 42 | adj[b].emplace_back(a, weight); 43 | } 44 | 45 | void bfs_check(queue &q, queue &next_q, int node, int from, int new_dist, int add) { 46 | assert(add == 0 || add == 1); 47 | 48 | if (new_dist < dist[node]) { 49 | dist[node] = new_dist; 50 | parent[node] = from; 51 | (add == 0 ? q : next_q).push(node); 52 | } 53 | } 54 | 55 | void bfs(const vector &source) { 56 | if (n == 0) return; 57 | 58 | // Two queues are needed for 0-1 BFS. 59 | queue q, next_q; 60 | dist.assign(n, INF); 61 | parent.assign(n, -1); 62 | 63 | for (int src : source) 64 | bfs_check(q, next_q, src, -1, 0, 0); 65 | 66 | int level = 0; 67 | 68 | while (!q.empty() || !next_q.empty()) { 69 | while (!q.empty()) { 70 | int top = q.front(); q.pop(); 71 | 72 | if (level > dist[top]) 73 | continue; 74 | 75 | for (edge &e : adj[top]) 76 | bfs_check(q, next_q, e.node, top, dist[top] + e.weight, e.weight); 77 | } 78 | 79 | q.swap(next_q); 80 | level++; 81 | } 82 | } 83 | }; 84 | 85 | 86 | int main() { 87 | ios::sync_with_stdio(false); 88 | #ifndef NEAL_DEBUG 89 | cin.tie(nullptr); 90 | #endif 91 | 92 | int N, M; 93 | cin >> N >> M; 94 | BFS bfs(N); 95 | 96 | for (int i = 0; i < M; i++) { 97 | int a, b, weight; 98 | cin >> a >> b >> weight; 99 | a--; b--; 100 | bfs.add_bidirectional_edge(a, b, weight); 101 | } 102 | 103 | long double begin = clock(); 104 | bfs.bfs({0}); 105 | cerr << "BFS time: " << (clock() - begin) / CLOCKS_PER_SEC << 's' << endl; 106 | 107 | int64_t total = 0; 108 | 109 | for (int i = 0; i < N; i++) 110 | total += bfs.dist[i]; 111 | 112 | cout << total << '\n'; 113 | } 114 | -------------------------------------------------------------------------------- /shortest_path/dijkstra.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | template 11 | struct Dijkstra { 12 | const T_weight W_INF = numeric_limits::max() / 2; 13 | 14 | struct edge { 15 | int node = -1; 16 | T_weight weight = 0; 17 | 18 | edge() {} 19 | 20 | edge(int _node, T_weight _weight) : node(_node), weight(_weight) {} 21 | }; 22 | 23 | struct state { 24 | T_weight dist; 25 | int node; 26 | 27 | state() {} 28 | 29 | state(T_weight _dist, int _node) : dist(_dist), node(_node) {} 30 | 31 | bool operator<(const state &other) const { 32 | return dist > other.dist; 33 | } 34 | }; 35 | 36 | int n; 37 | vector> adj; 38 | vector dist; 39 | vector parent; 40 | 41 | Dijkstra(int _n = 0) { 42 | init(_n); 43 | } 44 | 45 | void init(int _n) { 46 | n = _n; 47 | adj.assign(n, {}); 48 | } 49 | 50 | void add_directional_edge(int a, int b, T_weight weight) { 51 | adj[a].emplace_back(b, weight); 52 | } 53 | 54 | void add_bidirectional_edge(int a, int b, T_weight weight) { 55 | add_directional_edge(a, b, weight); 56 | add_directional_edge(b, a, weight); 57 | } 58 | 59 | void dijkstra_check(priority_queue &pq, int node, int from, T_weight new_dist) { 60 | if (new_dist < dist[node]) { 61 | dist[node] = new_dist; 62 | parent[node] = from; 63 | pq.emplace(new_dist, node); 64 | } 65 | } 66 | 67 | void dijkstra(const vector &source) { 68 | if (n == 0) return; 69 | dist.assign(n, W_INF); 70 | parent.assign(n, -1); 71 | priority_queue pq; 72 | 73 | for (int src : source) 74 | dijkstra_check(pq, src, -1, 0); 75 | 76 | while (!pq.empty()) { 77 | state top = pq.top(); 78 | pq.pop(); 79 | 80 | if (top.dist > dist[top.node]) 81 | continue; 82 | 83 | for (edge &e : adj[top.node]) 84 | dijkstra_check(pq, e.node, top.node, top.dist + e.weight); 85 | } 86 | } 87 | }; 88 | 89 | 90 | int main() { 91 | ios::sync_with_stdio(false); 92 | #ifndef NEAL_DEBUG 93 | cin.tie(nullptr); 94 | #endif 95 | 96 | int N, M; 97 | cin >> N >> M; 98 | Dijkstra dijkstra(N); 99 | 100 | for (int i = 0; i < M; i++) { 101 | int a, b; 102 | int64_t weight; 103 | cin >> a >> b >> weight; 104 | a--; b--; 105 | dijkstra.add_bidirectional_edge(a, b, weight); 106 | } 107 | 108 | long double begin = clock(); 109 | dijkstra.dijkstra({0}); 110 | fprintf(stderr, "Dijkstra time: %.3Lfs\n", (clock() - begin) / CLOCKS_PER_SEC); 111 | 112 | int64_t total = 0; 113 | 114 | for (int i = 0; i < N; i++) 115 | total += dijkstra.dist[i]; 116 | 117 | cout << total << '\n'; 118 | } 119 | -------------------------------------------------------------------------------- /shortest_path/grid_bfs.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | const int INF = int(1e9) + 5; 10 | 11 | const int DIRS = 4; 12 | const int DR[DIRS] = {-1, 0, +1, 0}; 13 | const int DC[DIRS] = { 0, +1, 0, -1}; 14 | 15 | // const int DIRS = 8; 16 | // const int DR[DIRS] = {-1, -1, -1, 0, +1, +1, +1, 0}; 17 | // const int DC[DIRS] = {-1, 0, +1, +1, +1, 0, -1, -1}; 18 | 19 | struct state { 20 | int row = -1, col = -1; 21 | 22 | state() {} 23 | 24 | state(int _row, int _col) : row(_row), col(_col) {} 25 | }; 26 | 27 | template 28 | struct grid_bfs { 29 | int R, C; 30 | vector grid; 31 | vector> dist; 32 | vector> parent; 33 | 34 | grid_bfs(const vector &_grid = {}) { 35 | init(_grid); 36 | } 37 | 38 | void init(const vector &_grid = {}) { 39 | grid = _grid; 40 | R = int(grid.size()); 41 | C = grid.empty() ? 0 : int(grid[0].size()); 42 | } 43 | 44 | bool valid(int r, int c) { 45 | return 0 <= r && r < R && 0 <= c && c < C; 46 | } 47 | 48 | void bfs_check(queue &q, queue &next_q, const state &s, const state &from_s, int new_dist, int add) { 49 | assert(add == 0 || add == 1); 50 | 51 | if (new_dist < dist[s.row][s.col]) { 52 | dist[s.row][s.col] = new_dist; 53 | parent[s.row][s.col] = from_s; 54 | (add == 0 ? q : next_q).push(s); 55 | } 56 | } 57 | 58 | void bfs(const vector &source) { 59 | if (R == 0 || C == 0) return; 60 | 61 | // Two queues are needed for 0-1 BFS. 62 | queue q, next_q; 63 | dist.assign(R, vector(C, INF)); 64 | parent.assign(R, vector(C, state())); 65 | 66 | for (const state &src : source) 67 | bfs_check(q, next_q, src, state(), 0, 0); 68 | 69 | int level = 0; 70 | 71 | while (!q.empty() || !next_q.empty()) { 72 | while (!q.empty()) { 73 | state top = q.front(); q.pop(); 74 | int r = top.row, c = top.col; 75 | 76 | if (level > dist[r][c]) 77 | continue; 78 | 79 | for (int dir = 0; dir < DIRS; dir++) { 80 | int nr = r + DR[dir]; 81 | int nc = c + DC[dir]; 82 | 83 | // TODO: If valid, also determine whether it's allowed to travel from r, c to nr, nc. 84 | if (valid(nr, nc)) { 85 | // TODO: Determine if edge weights need to be adjusted. 86 | int add = 1; 87 | bfs_check(q, next_q, state(nr, nc), top, dist[r][c] + add, add); 88 | } 89 | } 90 | } 91 | 92 | q.swap(next_q); 93 | level++; 94 | } 95 | } 96 | }; 97 | 98 | 99 | int main() { 100 | grid_bfs bfs; 101 | bfs.bfs({}); 102 | } 103 | -------------------------------------------------------------------------------- /sqrt/mo.cc: -------------------------------------------------------------------------------- 1 | // Solution to https://codeforces.com/contest/86/problem/D 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | using mo_value = int; 10 | using mo_answer = int64_t; 11 | 12 | // TODO: re-implement this struct. 13 | struct mo_state { 14 | const vector &values; 15 | 16 | vector freq; 17 | int64_t sum; 18 | 19 | mo_state(const vector &_values) : values(_values) { 20 | int maximum = values.empty() ? 0 : *max_element(values.begin(), values.end()); 21 | freq.assign(maximum + 1, 0); 22 | sum = 0; 23 | } 24 | 25 | void add_left(int index) { 26 | mo_value x = values[index]; 27 | sum += int64_t(2 * freq[x] + 1) * x; 28 | freq[x]++; 29 | } 30 | 31 | void add_right(int index) { 32 | add_left(index); 33 | } 34 | 35 | void remove_left(int index) { 36 | mo_value x = values[index]; 37 | freq[x]--; 38 | sum -= int64_t(2 * freq[x] + 1) * x; 39 | } 40 | 41 | void remove_right(int index) { 42 | remove_left(index); 43 | } 44 | 45 | mo_answer get_answer() const { 46 | return sum; 47 | } 48 | }; 49 | 50 | struct mo_query { 51 | int start, end, block, index; 52 | 53 | mo_query() : start(0), end(0) {} 54 | 55 | mo_query(int _start, int _end) : start(_start), end(_end) {} 56 | 57 | bool operator<(const mo_query &other) const { 58 | if (block != other.block) 59 | return block < other.block; 60 | 61 | return block % 2 == 0 ? end < other.end : end > other.end; 62 | } 63 | }; 64 | 65 | struct mo { 66 | int n; 67 | vector values; 68 | 69 | mo(const vector &_values = {}) : values(_values) { 70 | n = int(values.size()); 71 | } 72 | 73 | void update_state(mo_state &state, const mo_query &first, const mo_query &second) const { 74 | if (max(first.start, second.start) >= min(first.end, second.end)) { 75 | for (int i = first.start; i < first.end; i++) 76 | state.remove_left(i); 77 | 78 | for (int i = second.start; i < second.end; i++) 79 | state.add_right(i); 80 | 81 | return; 82 | } 83 | 84 | for (int i = first.start - 1; i >= second.start; i--) 85 | state.add_left(i); 86 | 87 | for (int i = first.end; i < second.end; i++) 88 | state.add_right(i); 89 | 90 | for (int i = first.start; i < second.start; i++) 91 | state.remove_left(i); 92 | 93 | for (int i = first.end - 1; i >= second.end; i--) 94 | state.remove_right(i); 95 | } 96 | 97 | vector solve(vector queries) const { 98 | int block_size = int(1.5 * n / sqrt(max(int(queries.size()), 1)) + 1); 99 | 100 | for (int i = 0; i < int(queries.size()); i++) { 101 | queries[i].index = i; 102 | queries[i].block = queries[i].start / block_size; 103 | } 104 | 105 | sort(queries.begin(), queries.end()); 106 | mo_state state(values); 107 | mo_query last_query; 108 | vector answers(queries.size()); 109 | 110 | for (mo_query &q : queries) { 111 | update_state(state, last_query, q); 112 | answers[q.index] = state.get_answer(); 113 | last_query = q; 114 | } 115 | 116 | return answers; 117 | } 118 | }; 119 | 120 | 121 | int main() { 122 | int N, Q; 123 | scanf("%d %d", &N, &Q); 124 | vector A(N); 125 | 126 | for (mo_value &a : A) 127 | scanf("%d", &a); 128 | 129 | mo solver(A); 130 | vector queries(Q); 131 | 132 | for (mo_query &qry : queries) { 133 | scanf("%d %d", &qry.start, &qry.end); 134 | qry.start--; 135 | } 136 | 137 | vector answers = solver.solve(queries); 138 | 139 | for (mo_answer &answer : answers) 140 | printf("%lld\n", (long long) answer); 141 | } 142 | -------------------------------------------------------------------------------- /sqrt/search_buckets.cc: -------------------------------------------------------------------------------- 1 | // TODO: pragmas may help make this faster. 2 | #pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math,inline") 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | // search_buckets provides two operations on an array: 13 | // 1) set array[i] = x 14 | // 2) count how many i in [start, end) satisfy array[i] < value 15 | // Both operations take sqrt(n log n) time. Amazingly, because of the cache efficiency this is faster than the online 16 | // (log n)^2 algorithm until n = 2-5 million. 17 | template 18 | struct search_buckets { 19 | // values are just the values in order. buckets are sorted in segments of bucket_size (last segment may be smaller) 20 | int n, bucket_size; 21 | vector values, buckets; 22 | 23 | search_buckets(const vector &initial = {}) { 24 | init(initial); 25 | } 26 | 27 | int get_bucket_start(int index) const { 28 | return index - index % bucket_size; 29 | } 30 | 31 | int get_bucket_end_from_start(int bucket_start) const { 32 | return min(bucket_start + bucket_size, n); 33 | } 34 | 35 | void init(const vector &initial) { 36 | values = buckets = initial; 37 | n = int(values.size()); 38 | bucket_size = int(3 * sqrt(n * log(n + 1)) + 1); 39 | cerr << "Bucket size: " << bucket_size << endl; 40 | 41 | for (int start = 0; start < n; start += bucket_size) 42 | sort(buckets.begin() + start, buckets.begin() + get_bucket_end_from_start(start)); 43 | } 44 | 45 | int bucket_count_less_than(int bucket_start, T value) const { 46 | auto begin = buckets.begin() + bucket_start; 47 | auto end = buckets.begin() + get_bucket_end_from_start(bucket_start); 48 | return int(lower_bound(begin, end, value) - begin); 49 | } 50 | 51 | int count_less_than(int start, int end, T value) const { 52 | int count = 0; 53 | int bucket_start = get_bucket_start(start); 54 | int bucket_end = get_bucket_end_from_start(bucket_start); 55 | 56 | if (start - bucket_start < bucket_end - start) { 57 | while (start > bucket_start) 58 | count -= values[--start] < value; 59 | } else { 60 | while (start < bucket_end) 61 | count += values[start++] < value; 62 | } 63 | 64 | bucket_start = get_bucket_start(end); 65 | bucket_end = get_bucket_end_from_start(bucket_start); 66 | 67 | if (end - bucket_start < bucket_end - end) { 68 | while (end > bucket_start) 69 | count += values[--end] < value; 70 | } else { 71 | while (end < bucket_end) 72 | count -= values[end++] < value; 73 | } 74 | 75 | while (start < end) { 76 | count += bucket_count_less_than(start, value); 77 | start = get_bucket_end_from_start(start); 78 | } 79 | 80 | assert(start == end); 81 | return count; 82 | } 83 | 84 | int prefix_count_less_than(int length, T value) const { 85 | return count_less_than(0, length, value); 86 | } 87 | 88 | void modify(int index, T value) { 89 | int bucket_start = get_bucket_start(index); 90 | int old_pos = bucket_start + bucket_count_less_than(bucket_start, values[index]); 91 | int new_pos = bucket_start + bucket_count_less_than(bucket_start, value); 92 | 93 | if (old_pos < new_pos) { 94 | copy(buckets.begin() + old_pos + 1, buckets.begin() + new_pos, buckets.begin() + old_pos); 95 | new_pos--; 96 | // memmove(&buckets[old_pos], &buckets[old_pos + 1], (new_pos - old_pos) * sizeof(T)); 97 | } else { 98 | copy_backward(buckets.begin() + new_pos, buckets.begin() + old_pos, buckets.begin() + old_pos + 1); 99 | // memmove(&buckets[new_pos + 1], &buckets[new_pos], (old_pos - new_pos) * sizeof(T)); 100 | } 101 | 102 | buckets[new_pos] = value; 103 | values[index] = value; 104 | } 105 | }; 106 | 107 | 108 | // Solution to https://www.spoj.com/problems/RACETIME 109 | 110 | int main() { 111 | int N, Q; 112 | scanf("%d %d", &N, &Q); 113 | vector initial(N); 114 | 115 | for (int &a : initial) 116 | scanf("%d", &a); 117 | 118 | search_buckets buckets(initial); 119 | 120 | for (int q = 0; q < Q; q++) { 121 | char type; 122 | int start, end, value; 123 | scanf(" %c", &type); 124 | 125 | if (type == 'M') { 126 | scanf("%d %d", &start, &value); 127 | start--; 128 | buckets.modify(start, value); 129 | } else if (type == 'C') { 130 | scanf("%d %d %d", &start, &end, &value); 131 | start--; 132 | printf("%d\n", buckets.count_less_than(start, end, value + 1)); 133 | } else { 134 | assert(false); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /strings/edit_distance.cc: -------------------------------------------------------------------------------- 1 | // https://en.wikipedia.org/wiki/Edit_distance 2 | // https://en.wikipedia.org/wiki/Levenshtein_distance 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | using namespace std; 19 | 20 | const int INF = int(1e9) + 5; 21 | 22 | int edit_distance_quadratic_memory(const string &S, const string &T) { 23 | int n = int(S.size()); 24 | int m = int(T.size()); 25 | vector> dp(n + 1, vector(m + 1, INF)); 26 | 27 | for (int i = 0; i <= n; i++) 28 | dp[i][0] = i; 29 | 30 | for (int j = 0; j <= m; j++) 31 | dp[0][j] = j; 32 | 33 | for (int i = 0; i < n; i++) 34 | for (int j = 0; j < m; j++) 35 | dp[i + 1][j + 1] = min({dp[i + 1][j] + 1, dp[i][j + 1] + 1, dp[i][j] + (S[i] != T[j])}); 36 | 37 | return dp[n][m]; 38 | } 39 | 40 | int edit_distance(const string &S, const string &T) { 41 | int n = int(S.size()); 42 | int m = int(T.size()); 43 | vector dp(m + 1); 44 | iota(dp.begin(), dp.end(), 0); 45 | 46 | for (int i = 0; i < n; i++) { 47 | vector ndp(m + 1, INF); 48 | ndp[0] = i + 1; 49 | 50 | for (int j = 0; j < m; j++) 51 | ndp[j + 1] = min({ndp[j] + 1, dp[j + 1] + 1, dp[j] + (S[i] != T[j])}); 52 | 53 | dp.swap(ndp); 54 | } 55 | 56 | return dp[m]; 57 | } 58 | 59 | vector construct_edit_distance(const string &S, const string &T) { 60 | int n = int(S.size()); 61 | int m = int(T.size()); 62 | vector> dp(n + 1, vector(m + 1, INF)); 63 | 64 | for (int i = 0; i <= n; i++) 65 | dp[i][0] = i; 66 | 67 | for (int j = 0; j <= m; j++) 68 | dp[0][j] = j; 69 | 70 | for (int i = 0; i < n; i++) 71 | for (int j = 0; j < m; j++) 72 | dp[i + 1][j + 1] = min({dp[i + 1][j] + 1, dp[i][j + 1] + 1, dp[i][j] + (S[i] != T[j])}); 73 | 74 | vector left = {S}, right = {T}; 75 | 76 | while (n > 0 || m > 0) { 77 | if (n > 0 && dp[n][m] == dp[n - 1][m] + 1) { 78 | n--; 79 | string str = left.back(); 80 | str.erase(str.begin() + n); 81 | left.push_back(str); 82 | } else if (m > 0 && dp[n][m] == dp[n][m - 1] + 1) { 83 | m--; 84 | string str = right.back(); 85 | str.erase(str.begin() + m); 86 | right.push_back(str); 87 | } else if (n > 0 && m > 0 && dp[n][m] == dp[n - 1][m - 1] + (S[n - 1] != T[m - 1])) { 88 | n--; 89 | m--; 90 | 91 | if (S[n] != T[m]) { 92 | string str = left.back(); 93 | str[n] = T[m]; 94 | left.push_back(str); 95 | } 96 | } else { 97 | assert(false); 98 | } 99 | } 100 | 101 | assert(left.back() == right.back()); 102 | right.pop_back(); 103 | 104 | while (!right.empty()) { 105 | left.push_back(right.back()); 106 | right.pop_back(); 107 | } 108 | 109 | return left; 110 | } 111 | 112 | int main() { 113 | ios::sync_with_stdio(false); 114 | #ifndef NEAL_DEBUG 115 | cin.tie(nullptr); 116 | #endif 117 | 118 | string S, T; 119 | cin >> S >> T; 120 | int dist = edit_distance(S, T); 121 | cout << dist << '\n'; 122 | vector answer = construct_edit_distance(S, T); 123 | 124 | for (string &str : answer) 125 | cout << str << '\n'; 126 | 127 | assert(edit_distance_quadratic_memory(S, T) == dist); 128 | assert(int(answer.size()) == dist + 1); 129 | assert(answer.front() == S && answer.back() == T); 130 | 131 | for (int i = 0; i < dist; i++) 132 | assert(edit_distance(answer[i], answer[i + 1]) == 1); 133 | } 134 | -------------------------------------------------------------------------------- /strings/kmp.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | namespace KMP { 9 | // Returns the next length to search from (the longest suffix of the current string that is a prefix of the pattern) 10 | // after starting from the prefix `len` and adding char `c`. 11 | // Runs in worst case O(len) but amortizes to O(1) in most situations. 12 | template 13 | int get_link(const T &pattern, const vector &fail, int len, const T_elem &c) { 14 | while (len > 0 && pattern[len] != c) 15 | len = fail[len]; 16 | 17 | if (pattern[len] == c) 18 | len++; 19 | 20 | return len; 21 | } 22 | 23 | // Computes the failure function on `pattern` so that we can search for it in future strings. 24 | template 25 | vector compute_failure_function(const T &pattern) { 26 | // fail[i] = for the prefix [0, i) of `pattern`, the length of the longest proper prefix that is also a suffix. 27 | int n = int(pattern.size()); 28 | vector fail(n + 1, 0); 29 | int len = 0; 30 | 31 | for (int i = 1; i < n; i++) { 32 | len = get_link(pattern, fail, len, pattern[i]); 33 | fail[i + 1] = len; 34 | } 35 | 36 | return fail; 37 | } 38 | 39 | template 40 | vector find_matches(const T &pattern, const T &text, const vector &fail) { 41 | if (pattern.size() > text.size()) 42 | return {}; 43 | 44 | vector matches; 45 | int n = int(pattern.size()), m = int(text.size()); 46 | int len = 0; 47 | 48 | for (int i = 0; i < m; i++) { 49 | len = get_link(pattern, fail, len, text[i]); 50 | 51 | // Check for a match whose last character is at index i. 52 | if (len == n) { 53 | matches.push_back(i - (n - 1)); 54 | len = fail[len]; 55 | } 56 | } 57 | 58 | return matches; 59 | } 60 | 61 | // Finds all indices where `pattern` occurs within `text`. 62 | template 63 | vector find_matches(const T &pattern, const T &text) { 64 | return find_matches(pattern, text, compute_failure_function(pattern)); 65 | } 66 | } 67 | 68 | int main() { 69 | ios::sync_with_stdio(false); 70 | #ifndef NEAL_DEBUG 71 | cin.tie(nullptr); 72 | #endif 73 | 74 | string pattern, text; 75 | cin >> pattern >> text; 76 | vector matches = KMP::find_matches(pattern, text); 77 | 78 | for (int match : matches) 79 | cout << match << '\n'; 80 | } 81 | -------------------------------------------------------------------------------- /strings/trie.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | template 10 | struct array_trie { 11 | struct trie_node { 12 | array child; 13 | int words_here = 0, starting_with = 0; 14 | 15 | trie_node() { 16 | memset(&child[0], -1, ALPHABET * sizeof(int)); 17 | } 18 | }; 19 | 20 | static const int ROOT = 0; 21 | 22 | vector nodes = {trie_node()}; 23 | 24 | array_trie(int total_length = -1) { 25 | if (total_length >= 0) 26 | nodes.reserve(total_length + 1); 27 | } 28 | 29 | int get_or_create_child(int node, int c) { 30 | if (nodes[node].child[c] < 0) { 31 | nodes[node].child[c] = int(nodes.size()); 32 | nodes.emplace_back(); 33 | } 34 | 35 | return nodes[node].child[c]; 36 | } 37 | 38 | int build(const string &word, int delta) { 39 | int node = ROOT; 40 | 41 | for (char ch : word) { 42 | nodes[node].starting_with += delta; 43 | node = get_or_create_child(node, ch - MIN_CHAR); 44 | } 45 | 46 | nodes[node].starting_with += delta; 47 | return node; 48 | } 49 | 50 | int add(const string &word) { 51 | int node = build(word, +1); 52 | nodes[node].words_here++; 53 | return node; 54 | } 55 | 56 | int erase(const string &word) { 57 | int node = build(word, -1); 58 | nodes[node].words_here--; 59 | return node; 60 | } 61 | 62 | int find(const string &str) const { 63 | int node = ROOT; 64 | 65 | for (char ch : str) { 66 | node = nodes[node].child[ch - MIN_CHAR]; 67 | 68 | if (node < 0) 69 | break; 70 | } 71 | 72 | return node; 73 | } 74 | 75 | // Given a string, how many words in the trie are prefixes of the string? 76 | int count_prefixes(const string &str, bool include_full) const { 77 | int node = ROOT, count = 0; 78 | 79 | for (char ch : str) { 80 | count += nodes[node].words_here; 81 | node = nodes[node].child[ch - MIN_CHAR]; 82 | 83 | if (node < 0) 84 | break; 85 | } 86 | 87 | if (include_full && node >= 0) 88 | count += nodes[node].words_here; 89 | 90 | return count; 91 | } 92 | 93 | // Given a string, how many words in the trie start with the given string? 94 | int count_starting_with(const string &str, bool include_full) const { 95 | int node = find(str); 96 | 97 | if (node < 0) 98 | return 0; 99 | 100 | return nodes[node].starting_with - (include_full ? 0 : nodes[node].words_here); 101 | } 102 | }; 103 | 104 | 105 | int main() { 106 | ios::sync_with_stdio(false); 107 | #ifndef NEAL_DEBUG 108 | cin.tie(nullptr); 109 | #endif 110 | 111 | int N; 112 | cin >> N; 113 | array_trie trie; 114 | vector strings(N); 115 | 116 | for (int i = 0; i < N; i++) { 117 | cin >> strings[i]; 118 | cout << trie.count_prefixes(strings[i], true) << ' ' << trie.count_starting_with(strings[i], true) << '\n'; 119 | trie.add(strings[i]); 120 | 121 | if (i >= N / 2) 122 | trie.erase(strings[i - N / 2]); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /strings/z_algorithm.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // Also known as "extended KMP" 9 | template 10 | vector z_algorithm(const T &pattern) { 11 | // Z[i] = for the suffix [i, n) of pattern, the longest prefix that is also a prefix of pattern. 12 | int n = int(pattern.size()); 13 | vector Z(n, 0); 14 | Z[0] = n; 15 | int loc = 1; 16 | 17 | for (int i = 1; i < n; i++) { 18 | if (i < loc + Z[loc]) 19 | Z[i] = min(Z[i - loc], loc + Z[loc] - i); 20 | 21 | while (i + Z[i] < n && pattern[Z[i]] == pattern[i + Z[i]]) 22 | Z[i]++; 23 | 24 | // Find the location with the furthest-reaching umbrella. 25 | if (i + Z[i] > loc + Z[loc]) 26 | loc = i; 27 | } 28 | 29 | return Z; 30 | } 31 | 32 | int main() { 33 | ios::sync_with_stdio(false); 34 | #ifndef NEAL_DEBUG 35 | cin.tie(nullptr); 36 | #endif 37 | 38 | string pattern, text; 39 | cin >> pattern >> text; 40 | int n = int(pattern.size()), m = int(text.size()); 41 | vector Z = z_algorithm(pattern + text); 42 | 43 | for (int i = 0; i < m; i++) 44 | if (Z[i + n] >= n) 45 | // Found a match starting at index i of text 46 | cout << i << '\n'; 47 | } 48 | -------------------------------------------------------------------------------- /tree_centroid/basic_template.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | struct edge { 9 | int node = -1; 10 | int64_t weight = 0; 11 | 12 | edge() {} 13 | 14 | edge(int _node, int64_t _weight) : node(_node), weight(_weight) {} 15 | }; 16 | 17 | struct centroid_decomposition { 18 | int N; 19 | vector> adj; 20 | vector depth; 21 | vector subtree_size; 22 | vector centroid_parent; 23 | vector subroot; 24 | vector nodes; 25 | 26 | centroid_decomposition(int _N = 0) { 27 | init(_N); 28 | } 29 | 30 | void init(int _N) { 31 | N = _N; 32 | adj.assign(N, {}); 33 | depth.resize(N); 34 | subtree_size.resize(N); 35 | centroid_parent.assign(N, -1); 36 | subroot.resize(N); 37 | } 38 | 39 | void add_edge(int u, int v, int64_t weight = 0) { 40 | adj[u].emplace_back(v, weight); 41 | adj[v].emplace_back(u, weight); 42 | } 43 | 44 | void erase_edge(int from, int to) { 45 | for (edge &e : adj[from]) 46 | if (e.node == to) { 47 | swap(e, adj[from].back()); 48 | adj[from].pop_back(); 49 | return; 50 | } 51 | 52 | assert(false); 53 | } 54 | 55 | int dfs(int node, int parent = -1, int sub = -1, int64_t weight = 0) { 56 | if (parent < 0) { 57 | sub = node; 58 | nodes.clear(); 59 | } 60 | 61 | depth[node] = parent < 0 ? 0 : depth[parent] + 1; 62 | subtree_size[node] = 1; 63 | subroot[node] = sub; 64 | nodes.push_back(node); 65 | 66 | for (edge &e : adj[node]) 67 | if (e.node != parent) 68 | subtree_size[node] += dfs(e.node, node, parent < 0 ? e.node : sub, weight + e.weight); 69 | 70 | return subtree_size[node]; 71 | } 72 | 73 | int centroid(int root) { 74 | int n = dfs(root); 75 | bool found; 76 | 77 | // Repeatedly move to the subtree that is at least half of the tree, if such a subtree exists. 78 | do { 79 | found = false; 80 | 81 | for (edge &e : adj[root]) 82 | if (subtree_size[e.node] <= subtree_size[root] && 2 * subtree_size[e.node] >= n) { 83 | root = e.node; 84 | found = true; 85 | break; 86 | } 87 | } while (found); 88 | 89 | return root; 90 | } 91 | 92 | void solve(int root) { 93 | root = centroid(root); 94 | 95 | for (int node : nodes) 96 | if (node != root) 97 | centroid_parent[node] = root; 98 | 99 | // TODO: either compute the answer for the whole tree here by calling `dfs(root)`, or compute it for each 100 | // subtree below by calling `dfs(e.node)`. 101 | 102 | for (edge &e : adj[root]) { 103 | erase_edge(e.node, root); 104 | // TODO: either compute the answer for the subtree of `e.node` here, or compute it for the whole tree above. 105 | // If computing for the whole tree above, we can move the `erase_edge` call to the loop below instead. 106 | } 107 | 108 | // Recurse after solving root, so that edge erasures don't cause incorrect results. 109 | for (edge &e : adj[root]) 110 | solve(e.node); 111 | } 112 | }; 113 | 114 | int main() { 115 | ios::sync_with_stdio(false); 116 | #ifndef NEAL_DEBUG 117 | cin.tie(nullptr); 118 | #endif 119 | 120 | int N; 121 | cin >> N; 122 | centroid_decomposition CD(N); 123 | 124 | for (int i = 0; i < N - 1; i++) { 125 | int u, v; 126 | cin >> u >> v; 127 | u--; v--; 128 | CD.add_edge(u, v); 129 | } 130 | 131 | CD.solve(0); 132 | } 133 | -------------------------------------------------------------------------------- /tree_centroid/subtract_subtrees_template.cc: -------------------------------------------------------------------------------- 1 | // Solves the following: given a weighted tree of N nodes and a number K, how many paths in the tree have weight <= K? 2 | // Runs in O(N log^2 N) time. 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | struct edge { 11 | int node = -1; 12 | int64_t weight = 0; 13 | 14 | edge() {} 15 | 16 | edge(int _node, int64_t _weight) : node(_node), weight(_weight) {} 17 | }; 18 | 19 | struct centroid_decomposition { 20 | int N; 21 | int64_t K; 22 | vector> adj; 23 | vector depth; 24 | vector subtree_size; 25 | vector centroid_parent; 26 | vector subroot; 27 | vector nodes; 28 | vector weights; 29 | 30 | centroid_decomposition(int _N = 0) { 31 | init(_N); 32 | } 33 | 34 | void init(int _N) { 35 | N = _N; 36 | adj.assign(N, {}); 37 | depth.resize(N); 38 | subtree_size.resize(N); 39 | centroid_parent.assign(N, -1); 40 | subroot.resize(N); 41 | } 42 | 43 | void add_edge(int u, int v, int64_t weight = 0) { 44 | adj[u].emplace_back(v, weight); 45 | adj[v].emplace_back(u, weight); 46 | } 47 | 48 | void erase_edge(int from, int to) { 49 | for (edge &e : adj[from]) 50 | if (e.node == to) { 51 | swap(e, adj[from].back()); 52 | adj[from].pop_back(); 53 | return; 54 | } 55 | 56 | assert(false); 57 | } 58 | 59 | int dfs(int node, int parent = -1, int sub = -1, int64_t weight = 0) { 60 | if (parent < 0) { 61 | sub = node; 62 | nodes.clear(); 63 | weights.clear(); 64 | } 65 | 66 | depth[node] = parent < 0 ? 0 : depth[parent] + 1; 67 | subtree_size[node] = 1; 68 | subroot[node] = sub; 69 | nodes.push_back(node); 70 | weights.push_back(weight); 71 | 72 | for (edge &e : adj[node]) 73 | if (e.node != parent) 74 | subtree_size[node] += dfs(e.node, node, parent < 0 ? e.node : sub, weight + e.weight); 75 | 76 | return subtree_size[node]; 77 | } 78 | 79 | int centroid(int root) { 80 | int n = dfs(root); 81 | bool found; 82 | 83 | // Repeatedly move to the subtree that is at least half of the tree, if such a subtree exists. 84 | do { 85 | found = false; 86 | 87 | for (edge &e : adj[root]) 88 | if (subtree_size[e.node] <= subtree_size[root] && 2 * subtree_size[e.node] >= n) { 89 | root = e.node; 90 | found = true; 91 | break; 92 | } 93 | } while (found); 94 | 95 | return root; 96 | } 97 | 98 | int64_t count_pairs(int root, int64_t weight_max) { 99 | int n = dfs(root); 100 | int64_t pairs = 0; 101 | sort(weights.begin(), weights.end()); 102 | assert(int(weights.size()) == n); 103 | 104 | for (int i = 0, j = n - 1; i < j; i++) { 105 | while (j > i && weights[i] + weights[j] > weight_max) 106 | j--; 107 | 108 | pairs += j - i; 109 | } 110 | 111 | return pairs; 112 | } 113 | 114 | int64_t solve(int root) { 115 | root = centroid(root); 116 | 117 | for (int node : nodes) 118 | if (node != root) 119 | centroid_parent[node] = root; 120 | 121 | // Compute the crossing pairs by counting all pairs and then subtracting pairs within the same subtree. 122 | int64_t pairs = count_pairs(root, K); 123 | 124 | for (edge &e : adj[root]) { 125 | erase_edge(e.node, root); 126 | pairs -= count_pairs(e.node, K - 2 * e.weight); 127 | } 128 | 129 | // Recurse after solving root, so that edge erasures don't cause incorrect results. 130 | for (edge &e : adj[root]) 131 | pairs += solve(e.node); 132 | 133 | return pairs; 134 | } 135 | }; 136 | 137 | int main() { 138 | ios::sync_with_stdio(false); 139 | #ifndef NEAL_DEBUG 140 | cin.tie(nullptr); 141 | #endif 142 | 143 | int N; 144 | int64_t K; 145 | cin >> N >> K; 146 | centroid_decomposition CD(N); 147 | CD.K = K; 148 | 149 | for (int i = 0; i < N - 1; i++) { 150 | int u, v; 151 | int64_t weight; 152 | cin >> u >> v >> weight; 153 | u--; v--; 154 | CD.add_edge(u, v, weight); 155 | } 156 | 157 | cout << CD.solve(0) << '\n'; 158 | } 159 | -------------------------------------------------------------------------------- /tree_dp/arrays_template_linear.cc: -------------------------------------------------------------------------------- 1 | // Solution to https://codeforces.com/contest/1249/problem/F 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | template 11 | bool maximize(T1 &a, const T2 &b) { 12 | if (a < b) { 13 | a = b; 14 | return true; 15 | } 16 | 17 | return false; 18 | } 19 | 20 | struct result { 21 | // dp[d] = the maximum possible weight when choosing some nodes out of our subtree such that the closest node to the 22 | // subtree root has depth at least d. In particular, dp[d] >= dp[d + 1] for all d. 23 | deque dp; 24 | 25 | result(int value = 0) { 26 | dp = {value}; 27 | } 28 | 29 | int size() const { 30 | return int(dp.size()); 31 | } 32 | 33 | int get(int index) const { 34 | return index < size() ? dp[index] : 0; 35 | } 36 | }; 37 | 38 | struct tree_dp { 39 | int N, K; 40 | vector A; 41 | vector> adj; 42 | vector results; 43 | 44 | tree_dp(int _N = 0) { 45 | init(_N); 46 | } 47 | 48 | void init(int _N) { 49 | N = _N; 50 | adj.assign(N, {}); 51 | } 52 | 53 | void add_edge(int u, int v) { 54 | adj[u].emplace_back(v); 55 | adj[v].emplace_back(u); 56 | } 57 | 58 | void extend(result &root) { 59 | // Shift the d dimension up by one. 60 | root.dp.push_front(root.dp.front()); 61 | } 62 | 63 | void attach(result &root, result &child) { 64 | if (root.size() < child.size()) 65 | swap(root, child); 66 | 67 | vector combined_dp(child.dp.begin(), child.dp.end()); 68 | 69 | for (int d = 0; d < child.size(); d++) { 70 | int min_other = max(K - d, d); 71 | maximize(combined_dp[d], root.dp[d] + child.get(min_other)); 72 | maximize(combined_dp[d], root.get(min_other) + child.dp[d]); 73 | } 74 | 75 | int maximum = 0; 76 | 77 | for (int i = child.size() - 1; i >= 0; i--) { 78 | maximize(maximum, combined_dp[i]); 79 | maximize(root.dp[i], maximum); 80 | } 81 | } 82 | 83 | void dfs(int node, int parent) { 84 | result ¤t = results[node]; 85 | current = result(A[node]); 86 | 87 | for (int neigh : adj[node]) 88 | if (neigh != parent) { 89 | dfs(neigh, node); 90 | result &child = results[neigh]; 91 | extend(child); 92 | attach(current, child); 93 | } 94 | } 95 | 96 | void solve() { 97 | results.assign(N, {}); 98 | dfs(0, -1); 99 | } 100 | }; 101 | 102 | int main() { 103 | ios::sync_with_stdio(false); 104 | #ifndef NEAL_DEBUG 105 | cin.tie(nullptr); 106 | #endif 107 | 108 | int N; 109 | cin >> N; 110 | tree_dp dp(N); 111 | cin >> dp.K; 112 | dp.K++; 113 | dp.A.resize(N); 114 | 115 | for (auto &a : dp.A) 116 | cin >> a; 117 | 118 | for (int i = 0; i < N - 1; i++) { 119 | int u, v; 120 | cin >> u >> v; 121 | u--; v--; 122 | dp.add_edge(u, v); 123 | } 124 | 125 | dp.solve(); 126 | cout << dp.results[0].dp.front() << '\n'; 127 | } 128 | -------------------------------------------------------------------------------- /tree_dp/arrays_template_quadratic.cc: -------------------------------------------------------------------------------- 1 | // Solution to https://codeforces.com/contest/1249/problem/F 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | template 10 | bool maximize(T1 &a, const T2 &b) { 11 | if (a < b) { 12 | a = b; 13 | return true; 14 | } 15 | 16 | return false; 17 | } 18 | 19 | const int INF = int(1e9) + 5; 20 | 21 | struct result { 22 | // dp[d] = the maximum weight to choose some nodes out of our subtree such that the highest node (closest to the 23 | // root) is depth d. 24 | vector dp; 25 | 26 | result(int value = -INF) { 27 | dp = {value}; 28 | } 29 | 30 | int size() const { 31 | return int(dp.size()); 32 | } 33 | 34 | int maximum() const { 35 | return *max_element(dp.begin(), dp.end()); 36 | } 37 | }; 38 | 39 | struct tree_dp { 40 | int N, K; 41 | vector A; 42 | vector> adj; 43 | vector results; 44 | 45 | tree_dp(int _N = 0) { 46 | init(_N); 47 | } 48 | 49 | void init(int _N) { 50 | N = _N; 51 | adj.assign(N, {}); 52 | } 53 | 54 | void add_edge(int u, int v) { 55 | adj[u].emplace_back(v); 56 | adj[v].emplace_back(u); 57 | } 58 | 59 | void extend(result &root) { 60 | // Shift the d dimension up by one. 61 | root.dp.insert(root.dp.begin(), -INF); 62 | } 63 | 64 | void attach(result &root, result &child) { 65 | result combined; 66 | combined.dp.assign(max(root.size(), child.size()), -INF); 67 | 68 | for (int i = 0; i < root.size(); i++) 69 | maximize(combined.dp[i], root.dp[i]); 70 | 71 | for (int i = 0; i < child.size(); i++) 72 | maximize(combined.dp[i], child.dp[i]); 73 | 74 | for (int x = 0; x < root.size(); x++) 75 | for (int y = max(K - x, 0); y < child.size(); y++) 76 | maximize(combined.dp[min(x, y)], root.dp[x] + child.dp[y]); 77 | 78 | root = combined; 79 | } 80 | 81 | void dfs(int node, int parent) { 82 | result ¤t = results[node]; 83 | current = result(A[node]); 84 | 85 | for (int neigh : adj[node]) 86 | if (neigh != parent) { 87 | dfs(neigh, node); 88 | result &child = results[neigh]; 89 | extend(child); 90 | attach(current, child); 91 | } 92 | } 93 | 94 | void solve() { 95 | results.assign(N, {}); 96 | dfs(0, -1); 97 | } 98 | }; 99 | 100 | int main() { 101 | ios::sync_with_stdio(false); 102 | #ifndef NEAL_DEBUG 103 | cin.tie(nullptr); 104 | #endif 105 | 106 | int N; 107 | cin >> N; 108 | tree_dp dp(N); 109 | cin >> dp.K; 110 | dp.K++; 111 | dp.A.resize(N); 112 | 113 | for (auto &a : dp.A) 114 | cin >> a; 115 | 116 | for (int i = 0; i < N - 1; i++) { 117 | int u, v; 118 | cin >> u >> v; 119 | u--; v--; 120 | dp.add_edge(u, v); 121 | } 122 | 123 | dp.solve(); 124 | cout << dp.results[0].maximum() << '\n'; 125 | } 126 | -------------------------------------------------------------------------------- /tree_dp/basic_template.cc: -------------------------------------------------------------------------------- 1 | // Solution to https://atcoder.jp/contests/dp/tasks/dp_p 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | const int MOD = int(1e9) + 7; 10 | 11 | struct result { 12 | int64_t black = 1, white = 1; 13 | 14 | int64_t either() const { 15 | return (black + white) % MOD; 16 | } 17 | }; 18 | 19 | struct tree_dp { 20 | int N; 21 | vector> adj; 22 | 23 | tree_dp(int _N = 0) { 24 | init(_N); 25 | } 26 | 27 | void init(int _N) { 28 | N = _N; 29 | adj.assign(N, {}); 30 | } 31 | 32 | void add_edge(int u, int v) { 33 | adj[u].emplace_back(v); 34 | adj[v].emplace_back(u); 35 | } 36 | 37 | // Warning: this setup is only recommended when the `result` struct is O(1) space. 38 | // Otherwise there is too much copying of `result` structs. In that case, use arrays_template.cc. 39 | result extend(result root) { 40 | return root; 41 | } 42 | 43 | result attach(result root, result child) { 44 | result combined; 45 | combined.black = root.black * child.white % MOD; 46 | combined.white = root.white * child.either() % MOD; 47 | return combined; 48 | } 49 | 50 | result dfs(int node, int parent) { 51 | result current; 52 | 53 | for (int neighbor : adj[node]) 54 | if (neighbor != parent) { 55 | result child = dfs(neighbor, node); 56 | current = attach(current, extend(child)); 57 | } 58 | 59 | return current; 60 | } 61 | 62 | result solve() { 63 | return dfs(0, -1); 64 | } 65 | }; 66 | 67 | int main() { 68 | ios::sync_with_stdio(false); 69 | #ifndef NEAL_DEBUG 70 | cin.tie(nullptr); 71 | #endif 72 | 73 | int N; 74 | cin >> N; 75 | tree_dp dp(N); 76 | 77 | for (int i = 0; i < N - 1; i++) { 78 | int u, v; 79 | cin >> u >> v; 80 | u--; v--; 81 | dp.add_edge(u, v); 82 | } 83 | 84 | cout << dp.solve().either() << '\n'; 85 | } 86 | -------------------------------------------------------------------------------- /tree_dp/up_down_tree_dp.cc: -------------------------------------------------------------------------------- 1 | // Solution to https://atcoder.jp/contests/dp/tasks/dp_v 2 | // We need to paint every vertex of a tree white or black such that the black vertices are a single connected component. 3 | // For every vertex v, find the number of ways to paint the tree such that v is painted black. 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | int MOD; 12 | 13 | struct tree_dp { 14 | int N; 15 | vector> adj; 16 | 17 | tree_dp(int _N = 0) { 18 | init(_N); 19 | } 20 | 21 | void init(int _N) { 22 | N = _N; 23 | adj.assign(N, {}); 24 | } 25 | 26 | void add_edge(int u, int v) { 27 | adj[u].emplace_back(v); 28 | adj[v].emplace_back(u); 29 | } 30 | 31 | // down[node] = number of ways to paint node's subtree where node must be painted black. 32 | // up[node] = number of ways to color parent's subtree of node, including all white. 33 | // combined[node] = answer for the whole tree when rooted at node. 34 | vector down; 35 | vector up; 36 | vector combined; 37 | 38 | void solve_down(int node, int parent) { 39 | vector &children = adj[node]; 40 | // Erase the edge from node to parent. 41 | children.erase(remove(children.begin(), children.end(), parent), children.end()); 42 | down[node] = 1; 43 | 44 | for (int child : children) { 45 | assert(child != parent); 46 | solve_down(child, node); 47 | down[node] = down[node] * (down[child] + 1) % MOD; 48 | } 49 | } 50 | 51 | void solve_up(int node, int parent) { 52 | vector &children = adj[node]; 53 | int n = int(children.size()); 54 | vector prefix(n + 1, 1); 55 | vector suffix(n + 1, 1); 56 | 57 | for (int i = 0; i < n; i++) 58 | prefix[i + 1] = prefix[i] * (down[children[i]] + 1) % MOD; 59 | 60 | for (int i = n - 1; i >= 0; i--) 61 | suffix[i] = suffix[i + 1] * (down[children[i]] + 1) % MOD; 62 | 63 | for (int i = 0; i < n; i++) 64 | up[children[i]] = (1 + prefix[i] * suffix[i + 1] % MOD * up[node]) % MOD; 65 | 66 | for (int child : children) { 67 | assert(child != parent); 68 | solve_up(child, node); 69 | } 70 | 71 | combined[node] = up[node] * down[node] % MOD; 72 | } 73 | 74 | void solve() { 75 | down.resize(N); 76 | solve_down(0, -1); 77 | 78 | up.resize(N); 79 | up[0] = 1; 80 | combined.resize(N); 81 | solve_up(0, -1); 82 | } 83 | }; 84 | 85 | int main() { 86 | ios::sync_with_stdio(false); 87 | #ifndef NEAL_DEBUG 88 | cin.tie(nullptr); 89 | #endif 90 | 91 | int N; 92 | cin >> N >> MOD; 93 | tree_dp dp(N); 94 | 95 | for (int i = 0; i < N - 1; i++) { 96 | int a, b; 97 | cin >> a >> b; 98 | a--; b--; 99 | dp.add_edge(a, b); 100 | } 101 | 102 | dp.solve(); 103 | 104 | for (int i = 0; i < N; i++) 105 | cout << dp.combined[i] << '\n'; 106 | } 107 | -------------------------------------------------------------------------------- /union_find/bipartite_union_find.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | struct bipartite_union_find { 9 | // When data[x] < 0, x is a root and -data[x] is its tree size. When data[x] >= 0, data[x] is x's parent. 10 | vector data; 11 | vector bipartite; // whether the component rooted at x is bipartite 12 | vector edge_parity; // the parity of the edge x -- parent[x] 13 | int components = 0; 14 | 15 | bipartite_union_find(int n = -1) { 16 | if (n >= 0) 17 | init(n); 18 | } 19 | 20 | void init(int n) { 21 | data.assign(n, -1); 22 | bipartite.assign(n, true); 23 | edge_parity.assign(n, false); 24 | components = n; 25 | } 26 | 27 | int find(int x) { 28 | if (data[x] < 0) 29 | return x; 30 | 31 | int root = find(data[x]); 32 | edge_parity[x] = edge_parity[x] ^ edge_parity[data[x]]; 33 | return data[x] = root; 34 | } 35 | 36 | int get_size(int x) { 37 | return -data[find(x)]; 38 | } 39 | 40 | // Returns true if x and y are in the same component. 41 | bool query_component(int x, int y) { 42 | return find(x) == find(y); 43 | } 44 | 45 | // Returns the parity status between x and y (0 = same, 1 = different). Requires them to be in the same component. 46 | bool query_parity(int x, int y) { 47 | bool same_component = query_component(x, y); 48 | assert(same_component); 49 | return edge_parity[x] ^ edge_parity[y]; 50 | } 51 | 52 | // Returns {union succeeded, edge consistent with bipartite conditions}. 53 | pair unite(int x, int y, bool different = true) { 54 | int x_root = find(x); 55 | int y_root = find(y); 56 | bool root_parity = edge_parity[x] ^ edge_parity[y] ^ different; 57 | x = x_root; 58 | y = y_root; 59 | 60 | if (x == y) { 61 | bool consistent = !root_parity; 62 | bipartite[x] = bipartite[x] && consistent; 63 | return {false, consistent}; 64 | } 65 | 66 | if (-data[x] < -data[y]) 67 | swap(x, y); 68 | 69 | data[x] += data[y]; 70 | data[y] = x; 71 | bipartite[x] = bipartite[x] && bipartite[y]; 72 | edge_parity[y] = root_parity; 73 | components--; 74 | return {true, true}; 75 | } 76 | 77 | // Add an assertion that x and y are different; i.e., a normal edge. 78 | pair add_different_edge(int x, int y) { 79 | return unite(x, y, true); 80 | } 81 | 82 | // Add an assertion that x and y are the same. 83 | pair add_same_edge(int x, int y) { 84 | return unite(x, y, false); 85 | } 86 | }; 87 | 88 | 89 | int main() { 90 | ios::sync_with_stdio(false); 91 | #ifndef NEAL_DEBUG 92 | cin.tie(nullptr); 93 | #endif 94 | 95 | int N, Q; 96 | cin >> N >> Q; 97 | bipartite_union_find UF(N); 98 | 99 | for (int q = 0; q < Q; q++) { 100 | int type, a, b; 101 | cin >> type >> a >> b; 102 | assert(1 <= min(a, b) && max(a, b) <= N); 103 | a--; b--; 104 | 105 | if (type == 1) { 106 | bool same_component = UF.query_component(a, b); 107 | 108 | if (same_component) 109 | cout << same_component << ' ' << UF.query_parity(a, b) << '\n'; 110 | else 111 | cout << same_component << '\n'; 112 | } else if (type == 2) { 113 | int e; 114 | cin >> e; 115 | pair result = UF.unite(a, b, e); 116 | cout << result.first << ' ' << result.second << '\n'; 117 | } else { 118 | assert(false); 119 | } 120 | } 121 | 122 | for (int i = 0; i < N; i++) 123 | cout << UF.bipartite[UF.find(i)]; 124 | 125 | cout << '\n'; 126 | } 127 | -------------------------------------------------------------------------------- /union_find/kruskal.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct union_find { 8 | // When data[x] < 0, x is a root and -data[x] is its tree size. When data[x] >= 0, data[x] is x's parent. 9 | vector data; 10 | int components = 0; 11 | 12 | union_find(int n = -1) { 13 | if (n >= 0) 14 | init(n); 15 | } 16 | 17 | void init(int n) { 18 | data.assign(n, -1); 19 | components = n; 20 | } 21 | 22 | int find(int x) { 23 | return data[x] < 0 ? x : data[x] = find(data[x]); 24 | } 25 | 26 | int get_size(int x) { 27 | return -data[find(x)]; 28 | } 29 | 30 | bool unite(int x, int y) { 31 | x = find(x); 32 | y = find(y); 33 | 34 | if (x == y) 35 | return false; 36 | 37 | if (-data[x] < -data[y]) 38 | swap(x, y); 39 | 40 | data[x] += data[y]; 41 | data[y] = x; 42 | components--; 43 | return true; 44 | } 45 | }; 46 | 47 | template 48 | struct kruskal { 49 | struct edge { 50 | int a, b; 51 | T_edge weight; 52 | int index = -1; 53 | bool in_tree = false; 54 | 55 | edge() {} 56 | 57 | edge(int _a, int _b, T_edge _weight, int _index = -1) : a(_a), b(_b), weight(_weight), index(_index) {} 58 | 59 | bool operator<(const edge &other) const { 60 | return weight < other.weight; 61 | } 62 | }; 63 | 64 | union_find UF; 65 | vector edges; 66 | vector original_in_tree; 67 | 68 | kruskal(int n = -1) { 69 | if (n >= 0) 70 | init(n); 71 | } 72 | 73 | void init(int n) { 74 | UF.init(n); 75 | edges = {}; 76 | } 77 | 78 | void add_edge(int a, int b, T_edge weight) { 79 | edges.emplace_back(a, b, weight, edges.size()); 80 | original_in_tree.push_back(false); 81 | } 82 | 83 | template 84 | T_sum solve() { 85 | sort(edges.begin(), edges.end()); 86 | T_sum total = 0; 87 | 88 | for (edge &e : edges) 89 | if (UF.unite(e.a, e.b)) { 90 | total += e.weight; 91 | e.in_tree = true; 92 | original_in_tree[e.index] = true; 93 | } 94 | 95 | return total; 96 | } 97 | }; 98 | 99 | 100 | int main() { 101 | 102 | } 103 | -------------------------------------------------------------------------------- /union_find/union_find_size.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | struct union_find { 9 | vector parent; 10 | vector size; 11 | int components = 0; 12 | 13 | union_find(int n = -1) { 14 | if (n >= 0) 15 | init(n); 16 | } 17 | 18 | void init(int n) { 19 | parent.resize(n); 20 | iota(parent.begin(), parent.end(), 0); 21 | size.assign(n, 1); 22 | components = n; 23 | } 24 | 25 | int find(int x) { 26 | return x == parent[x] ? x : parent[x] = find(parent[x]); 27 | } 28 | 29 | bool unite(int x, int y) { 30 | x = find(x); 31 | y = find(y); 32 | 33 | if (x == y) 34 | return false; 35 | 36 | if (size[x] < size[y]) 37 | swap(x, y); 38 | 39 | size[x] += size[y]; 40 | parent[y] = x; 41 | components--; 42 | return true; 43 | } 44 | }; 45 | 46 | 47 | int main() { 48 | ios::sync_with_stdio(false); 49 | #ifndef NEAL_DEBUG 50 | cin.tie(nullptr); 51 | #endif 52 | 53 | int N, Q; 54 | cin >> N >> Q; 55 | union_find UF(N); 56 | 57 | for (int q = 0; q < Q; q++) { 58 | int type, a, b; 59 | cin >> type >> a >> b; 60 | assert(1 <= min(a, b) && max(a, b) <= N); 61 | a--; b--; 62 | 63 | if (type == 1) 64 | cout << (UF.find(a) == UF.find(b)) << '\n'; 65 | else if (type == 2) 66 | cout << UF.unite(a, b) << '\n'; 67 | } 68 | } 69 | --------------------------------------------------------------------------------