From 4a333399abf593d22e9028e496addbca7c0de987 Mon Sep 17 00:00:00 2001 From: arielherself Date: Thu, 2 May 2024 13:31:31 +0800 Subject: [PATCH] backup --- init.lua => lua/config.lua | 284 +++----------------------- lua/overseer/template/user/cpp_cp.lua | 15 ++ lua/snippets/bit.lua | 23 +++ lua/snippets/cpp-include.lua | 237 +++++++++++++++++++++ lua/snippets/exgcd.lua | 93 +++++++++ lua/snippets/fhq-treap.lua | 176 ++++++++++++++++ lua/snippets/hash-deque.lua | 55 +++++ lua/snippets/hash-vec.lua | 72 +++++++ lua/snippets/init.lua | 181 ++++++++++++++++ lua/snippets/lpf.lua | 22 ++ lua/snippets/pollard-rho.lua | 91 +++++++++ lua/snippets/quick-union.lua | 31 +++ lua/snippets/segtree-generic.lua | 128 ++++++++++++ lua/snippets/sparse-table.lua | 25 +++ lua/snippets/tarjan.lua | 71 +++++++ 15 files changed, 1243 insertions(+), 261 deletions(-) rename init.lua => lua/config.lua (80%) create mode 100644 lua/overseer/template/user/cpp_cp.lua create mode 100644 lua/snippets/bit.lua create mode 100644 lua/snippets/cpp-include.lua create mode 100644 lua/snippets/exgcd.lua create mode 100644 lua/snippets/fhq-treap.lua create mode 100644 lua/snippets/hash-deque.lua create mode 100644 lua/snippets/hash-vec.lua create mode 100644 lua/snippets/init.lua create mode 100644 lua/snippets/lpf.lua create mode 100644 lua/snippets/pollard-rho.lua create mode 100644 lua/snippets/quick-union.lua create mode 100644 lua/snippets/segtree-generic.lua create mode 100644 lua/snippets/sparse-table.lua create mode 100644 lua/snippets/tarjan.lua diff --git a/init.lua b/lua/config.lua similarity index 80% rename from init.lua rename to lua/config.lua index c439cc8..9386653 100644 --- a/init.lua +++ b/lua/config.lua @@ -1,3 +1,4 @@ +vim.cmd("set pumblend=15") vim.cmd("set expandtab") vim.cmd("set tabstop=4") vim.cmd("set softtabstop=4") @@ -88,6 +89,15 @@ local plugins = { -- Additional lua configuration, makes nvim stuff amazing! 'folke/neodev.nvim', }, + opts = { + -- inlay_hints = { enabled = true, }, + -- codelens = { enabled = true, }, + }, + config = function(_, servers) + for server, opts in pairs(servers) do + require('lspconfig')[server].setup(opts) + end + end, }, { "hrsh7th/nvim-cmp", @@ -429,7 +439,7 @@ local plugins = { }, { 'Civitasv/cmake-tools.nvim' }, { 'p00f/cphelper.nvim' }, - { "savq/melange-nvim" }, + { "arielherself/melange-nvim"}, { 'hrsh7th/vim-vsnip' }, { 'octarect/telescope-menu.nvim' }, { @@ -444,8 +454,9 @@ local plugins = { }, config = true }, - { 'Exafunction/codeium.vim' }, + -- { 'Exafunction/codeium.vim' }, { "mistricky/codesnap.nvim", build = "make" }, + { 'rmagatti/goto-preview' }, } local opts = { } @@ -606,6 +617,9 @@ lspconfig.rust_analyzer.setup { ['rust-analyzer'] = {}, }, } +lspconfig.lua_ls.setup { + capabilities = capabilities +} -- Global mappings. -- See `:help vim.diagnostic.*` for documentation on any of the below functions @@ -661,7 +675,6 @@ require("lsp_signature").setup({}) vim.keymap.set({'i', 'n', 'v', 'x'}, '', '', {noremap=true}) vim.keymap.set({'i', 'n', 'v', 'x'}, '', '', {noremap=true}) -vim.keymap.set('i', '', 'PA') vim.keymap.set('i', '', 'ddi') vim.keymap.set('i', '', '^i') vim.keymap.set('i', '', 'ggVG') @@ -873,265 +886,9 @@ require('usage-tracker').setup({ telemetry_endpoint = "" -- you'll need to start the restapi for this feature }) -local function lines(str) - local result = {} - for line in str:gmatch '[^\n]+' do - table.insert(result, line) - end - return result -end -local ls = require('luasnip') -local snip = ls.snippet -local text = ls.text_node -local include_snippet = [[ -#pragma GCC optimize("Ofast") -///////////////////////////////////////////////////////// -/** - * Useful Macros - * by subcrip - * (requires C++17) - */ - -#include -using namespace std; - -/* macro helpers */ -#define __NARGS(...) std::tuple_size::value -#define __DECOMPOSE_S(a, x) auto x = a; -#define __DECOMPOSE_N(a, ...) auto [__VA_ARGS__] = a; -constexpr void __() {} -#define __AS_PROCEDURE(...) __(); __VA_ARGS__; __() -#define __as_typeof(container) decltype(container)::value_type - -/* type aliases */ -using ll = int64_t; -using ull = uint64_t; -using pii = pair; -using pil = pair; -using pli = pair; -using pll = pair; - -/* constants */ -constexpr int INF = 0x3f3f3f3f; -constexpr ll INFLL = 0x3f3f3f3f3f3f3f3fLL; -constexpr ll MDL = 1e9 + 7; -constexpr ll PRIME = 998'244'353; -constexpr ll MDL1 = 8784491; -constexpr ll MDL2 = PRIME; - -/* random */ - -mt19937 rd(chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count()); - -/* bit-wise operations */ -#define lowbit(x) ((x) & -(x)) -#define popcount(x) (__builtin_popcountll(ll(x))) -#define parity(x) (__builtin_parityll(ll(x))) -#define msp(x) (63LL - __builtin_clzll(ll(x))) -#define lsp(x) (__builtin_ctzll(ll(x))) - -/* arithmetic operations */ -#define mod(x, y) ((((x) % (y)) + (y)) % (y)) - -/* fast pairs */ -#define upair ull -#define umake(x, y) (ull(x) << 32 | (ull(y) & ((1ULL << 32) - 1))) -#define u1(p) ((p) >> 32) -#define u2(p) ((p) & ((1ULL << 32) - 1)) -#define ult std::less -#define ugt std::greater - -#define ipair ull -#define imake(x, y) (umake(x, y)) -#define i1(p) (int(u1(ll(p)))) -#define i2(p) (ll(u2(p) << 32) >> 32) -struct ilt { - bool operator()(const ipair& a, const ipair& b) const { - if (i1(a) == i1(b)) return i2(a) < i2(b); - else return i1(a) < i1(b); - } -}; -struct igt { - bool operator()(const ipair& a, const ipair& b) const { - if (i1(a) == i1(b)) return i2(a) > i2(b); - else return i1(a) > i1(b); - } -}; - -/* conditions */ -#define loop while (1) -#define if_or(var, val) if (!(var == val)) var = val; else -#define continue_or(var, val) __AS_PROCEDURE(if (var == val) continue; var = val;) -#define break_or(var, val) __AS_PROCEDURE(if (var == val) break; var = val;) - -/* hash */ -struct safe_hash { - // https://codeforces.com/blog/entry/62393 - static uint64_t splitmix64(uint64_t x) { - // http://xorshift.di.unimi.it/splitmix64.c - x += 0x9e3779b97f4a7c15; - x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; - x = (x ^ (x >> 27)) * 0x94d049bb133111eb; - return x ^ (x >> 31); - } - - size_t operator()(uint64_t x) const { - static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); - return splitmix64(x + FIXED_RANDOM); - } -}; - -struct pair_hash { - template - size_t operator()(const pair& a) const { - auto hash1 = safe_hash()(a.first); - auto hash2 = safe_hash()(a.second); - if (hash1 != hash2) { - return hash1 ^ hash2; - } - return hash1; - } -}; - -/* build data structures */ -#define unordered_counter(from, to) __AS_PROCEDURE(unordered_map<__as_typeof(from), size_t, safe_hash> to; for (auto&& x : from) ++to[x];) -#define counter(from, to, cmp) __AS_PROCEDURE(map<__as_typeof(from), size_t, cmp> to; for (auto&& x : from) ++to[x];) -#define pa(a) __AS_PROCEDURE(__typeof(a) pa; pa.push_back({}); for (auto&&x : a) pa.push_back(pa.back() + x);) -#define sa(a) __AS_PROCEDURE(__typeof(a) sa(a.size() + 1); {int n = a.size(); for (int i = n - 1; i >= 0; --i) sa[i] = sa[i + 1] + a[i];};) -#define adj(ch, n) __AS_PROCEDURE(vector> ch((n) + 1);) -#define edge(ch, u, v) __AS_PROCEDURE(ch[u].push_back(v), ch[v].push_back(u);) -#define Edge(ch, u, v) __AS_PROCEDURE(ch[u].push_back(v);) -template pair> discretize(Iterator __first, Iterator __last) { - set st(__first, __last); - size_t N = 0; - map mp; - for (auto&& x : st) mp[x] = ++N; - return {N, mp}; -} -template pair> unordered_discretize(Iterator __first, Iterator __last) { - set st(__first, __last); - size_t N = 0; - unordered_map mp; - for (auto&& x : st) mp[x] = ++N; - return {N, mp}; -} - -/* io */ -#define untie __AS_PROCEDURE(ios_base::sync_with_stdio(0), cin.tie(NULL)) -template void __read(T& x) { cin >> x; } -template void __read(T& x, U&... args) { cin >> x; __read(args...); } -#define read(type, ...) __AS_PROCEDURE(type __VA_ARGS__; __read(__VA_ARGS__);) -#define readvec(type, a, n) __AS_PROCEDURE(vector a(n); for (int i = 0; i < (n); ++i) cin >> a[i];) -#define putvec(a) __AS_PROCEDURE(for (auto&& x : a) cout << x << ' '; cout << endl;) -#define debug(x) __AS_PROCEDURE(cerr << #x" = " << (x) << endl;) -#define debugvec(a) __AS_PROCEDURE(cerr << #a" = "; for (auto&& x : a) cerr << x << ' '; cerr << endl;) -template ostream& operator<<(ostream& out, const pair& p) { - out << "{" << p.first << ", " << p.second << "}"; - return out; -} -template -void print_tuple_impl(std::basic_ostream& os, const Tuple& t, std::index_sequence) { - using swallow = int[]; // guaranties left to right order - (void)swallow { 0, (void(os << (Index == 0 ? "" : ", ") << std::get(t)), 0)... }; -} -template -decltype(auto) operator<<(std::basic_ostream& os, const std::tuple& t) { - os << "{"; - print_tuple_impl(os, t, std::index_sequence_for{}); - return os << "}"; -} -template ostream& operator<<(ostream& out, const vector& vec) { - for (auto&& i : vec) out << i << ' '; - return out; -} - -/* pops */ -#define poptop(q, ...) __AS_PROCEDURE(auto [__VA_ARGS__] = q.top(); q.pop();) -#define popback(q, ...) __AS_PROCEDURE(auto [__VA_ARGS__] = q.back(); q.pop_back();) -#define popfront(q, ...) __AS_PROCEDURE(auto [__VA_ARGS__] = q.front();q.pop_front();) - -/* math */ -constexpr inline int lg2(ll x) { return x == 0 ? -1 : sizeof(ll) * 8 - 1 - __builtin_clzll(x); } - -void __exgcd(ll a, ll b, ll& x, ll& y) { - if (b == 0) { - x = 1, y = 0; - return; - } - __exgcd(b, a % b, y, x); - y -= a / b * x; -} - -ll inverse(ll a, ll b) { - ll x, y; - __exgcd(a, b, x, y); - return mod(x, b); -} - -/* string algorithms */ -vector calc_next(string t) { // pi function of t - int n = (int)t.length(); - vector pi(n); - for (int i = 1; i < n; i++) { - int j = pi[i - 1]; - while (j > 0 && t[i] != t[j]) j = pi[j - 1]; - if (t[i] == t[j]) j++; - pi[i] = j; - } - return pi; -} -vector calc_z(string t) { // z function of t - int m = t.length(); - vector z; - z.push_back(m); - pair prev = {1, -1}; - for (int i = 1; i < m; ++i) { - if (z[i - prev.first] + i <= prev.second) { - z.push_back(z[i - prev.first]); - } else { - int j = max(i, prev.second + 1); - while (j < m && t[j] == t[j - i]) ++j; - z.push_back(j - i); - prev = {i, j - 1}; - } - } - return z; -} -vector kmp(string s, string t) { // find all t in s - string cur = t + '#' + s; - int sz1 = s.size(), sz2 = t.size(); - vector v; - vector lps = calc_next(cur); - for (int i = sz2 + 1; i <= sz1 + sz2; i++) { - if (lps[i] == sz2) v.push_back(i - 2 * sz2); - } - return v; -} -int period(string s) { // find the length of shortest recurring period - int n = s.length(); - auto z = calc_z(s); - for (int i = 1; i <= n / 2; ++i) { - if (n % i == 0 && z[i] == n - i) { - return i; - } - } - return n; -} -///////////////////////////////////////////////////////// -]] - -ls.add_snippets(nil, { - cpp = { - snip({ - trig = 'include', - namr = 'Useful Macros', - dscr = 'Useful Macros', - },{ - text(lines(include_snippet)) - }) - } -}) +-- my snippets +require('snippets') require('neo-tree').setup { filesystem = { @@ -1308,3 +1065,8 @@ require('codesnap').setup { code_font_family = "Fira Code", has_line_number = true, } + +require('goto-preview').setup { + default_mappings = true; +} + diff --git a/lua/overseer/template/user/cpp_cp.lua b/lua/overseer/template/user/cpp_cp.lua new file mode 100644 index 0000000..a1e59cc --- /dev/null +++ b/lua/overseer/template/user/cpp_cp.lua @@ -0,0 +1,15 @@ +return { + name = "c++ build (cp)", + builder = function() + -- Full path to current file (see :help expand()) + local file = vim.fn.expand("%:p") + return { + cmd = { "g++ -std=c++17 " .. file .. " -fsanitize=address -Ofast -Wall && ./a.out < std.in > std.out" }, + args = { file }, + components = { { "on_output_quickfix", open = true }, "default" }, + } + end, + condition = { + filetype = { "cpp" }, + }, +} diff --git a/lua/snippets/bit.lua b/lua/snippets/bit.lua new file mode 100644 index 0000000..5b37cb7 --- /dev/null +++ b/lua/snippets/bit.lua @@ -0,0 +1,23 @@ +return [[ +template +struct BIT { + int n; + vector c; + BIT(size_t n) : n(n), c(n + 1) {} + void add(size_t i, const T& k) { + while (i <= n) { + c[i] += k; + i += lowbit(i); + } + } + T getsum(size_t i) { + T res = {}; + while (i) { + res += c[i]; + i -= lowbit(i); + } + return res; + } +}; + +]] diff --git a/lua/snippets/cpp-include.lua b/lua/snippets/cpp-include.lua new file mode 100644 index 0000000..a25414a --- /dev/null +++ b/lua/snippets/cpp-include.lua @@ -0,0 +1,237 @@ +return [[ +#pragma GCC optimize("Ofast") +///////////////////////////////////////////////////////// +/** + * Useful Macros + * by subcrip + * (requires C++17) + */ + +#include +using namespace std; + +/* macro helpers */ +#define __NARGS(...) std::tuple_size::value +#define __DECOMPOSE_S(a, x) auto x = a; +#define __DECOMPOSE_N(a, ...) auto [__VA_ARGS__] = a; +constexpr void __() {} +#define __AS_PROCEDURE(...) __(); __VA_ARGS__; __() +#define __as_typeof(container) decltype(container)::value_type + +/* type aliases */ +using ll = int64_t; +using ull = uint64_t; +using pii = pair; +using pil = pair; +using pli = pair; +using pll = pair; + +/* constants */ +constexpr int INF = 0x3f3f3f3f; +constexpr ll INFLL = 0x3f3f3f3f3f3f3f3fLL; +constexpr ll MDL = 1e9 + 7; +constexpr ll PRIME = 998'244'353; +constexpr ll MDL1 = 8784491; +constexpr ll MDL2 = PRIME; + +/* random */ + +mt19937 rd(chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count()); + +/* bit-wise operations */ +#define lowbit(x) ((x) & -(x)) +#define popcount(x) (__builtin_popcountll(ll(x))) +#define parity(x) (__builtin_parityll(ll(x))) +#define msp(x) (63LL - __builtin_clzll(ll(x))) +#define lsp(x) (__builtin_ctzll(ll(x))) + +/* arithmetic operations */ +#define mod(x, y) ((((x) % (y)) + (y)) % (y)) + +/* fast pairs */ +#define upair ull +#define umake(x, y) (ull(x) << 32 | (ull(y) & ((1ULL << 32) - 1))) +#define u1(p) ((p) >> 32) +#define u2(p) ((p) & ((1ULL << 32) - 1)) +#define ult std::less +#define ugt std::greater + +#define ipair ull +#define imake(x, y) (umake(x, y)) +#define i1(p) (int(u1(ll(p)))) +#define i2(p) (ll(u2(p) << 32) >> 32) +struct ilt { + bool operator()(const ipair& a, const ipair& b) const { + if (i1(a) == i1(b)) return i2(a) < i2(b); + else return i1(a) < i1(b); + } +}; +struct igt { + bool operator()(const ipair& a, const ipair& b) const { + if (i1(a) == i1(b)) return i2(a) > i2(b); + else return i1(a) > i1(b); + } +}; + +/* conditions */ +#define loop while (1) +#define if_or(var, val) if (!(var == val)) var = val; else +#define continue_or(var, val) __AS_PROCEDURE(if (var == val) continue; var = val;) +#define break_or(var, val) __AS_PROCEDURE(if (var == val) break; var = val;) + +/* hash */ +struct safe_hash { + // https://codeforces.com/blog/entry/62393 + static uint64_t splitmix64(uint64_t x) { + // http://xorshift.di.unimi.it/splitmix64.c + x += 0x9e3779b97f4a7c15; + x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; + x = (x ^ (x >> 27)) * 0x94d049bb133111eb; + return x ^ (x >> 31); + } + + size_t operator()(uint64_t x) const { + static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); + return splitmix64(x + FIXED_RANDOM); + } +}; + +struct pair_hash { + template + size_t operator()(const pair& a) const { + auto hash1 = safe_hash()(a.first); + auto hash2 = safe_hash()(a.second); + if (hash1 != hash2) { + return hash1 ^ hash2; + } + return hash1; + } +}; + +/* build data structures */ +#define unordered_counter(from, to) __AS_PROCEDURE(unordered_map<__as_typeof(from), size_t, safe_hash> to; for (auto&& x : from) ++to[x];) +#define counter(from, to, cmp) __AS_PROCEDURE(map<__as_typeof(from), size_t, cmp> to; for (auto&& x : from) ++to[x];) +#define pa(a) __AS_PROCEDURE(__typeof(a) pa; pa.push_back({}); for (auto&&x : a) pa.push_back(pa.back() + x);) +#define sa(a) __AS_PROCEDURE(__typeof(a) sa(a.size() + 1); {int n = a.size(); for (int i = n - 1; i >= 0; --i) sa[i] = sa[i + 1] + a[i];};) +#define adj(ch, n) __AS_PROCEDURE(vector> ch((n) + 1);) +#define edge(ch, u, v) __AS_PROCEDURE(ch[u].push_back(v), ch[v].push_back(u);) +#define Edge(ch, u, v) __AS_PROCEDURE(ch[u].push_back(v);) +template pair> discretize(Iterator __first, Iterator __last) { + set st(__first, __last); + size_t N = 0; + map mp; + for (auto&& x : st) mp[x] = ++N; + return {N, mp}; +} +template pair> unordered_discretize(Iterator __first, Iterator __last) { + set st(__first, __last); + size_t N = 0; + unordered_map mp; + for (auto&& x : st) mp[x] = ++N; + return {N, mp}; +} + +/* io */ +#define untie __AS_PROCEDURE(ios_base::sync_with_stdio(0), cin.tie(NULL)) +template void __read(T& x) { cin >> x; } +template void __read(T& x, U&... args) { cin >> x; __read(args...); } +#define read(type, ...) __AS_PROCEDURE(type __VA_ARGS__; __read(__VA_ARGS__);) +#define readvec(type, a, n) __AS_PROCEDURE(vector a(n); for (int i = 0; i < (n); ++i) cin >> a[i];) +#define putvec(a) __AS_PROCEDURE(for (auto&& x : a) cout << x << ' '; cout << endl;) +#define debug(x) __AS_PROCEDURE(cerr << #x" = " << (x) << endl;) +#define debugvec(a) __AS_PROCEDURE(cerr << #a" = "; for (auto&& x : a) cerr << x << ' '; cerr << endl;) +template ostream& operator<<(ostream& out, const pair& p) { + out << "{" << p.first << ", " << p.second << "}"; + return out; +} +template +void print_tuple_impl(std::basic_ostream& os, const Tuple& t, std::index_sequence) { + using swallow = int[]; // guaranties left to right order + (void)swallow { 0, (void(os << (Index == 0 ? "" : ", ") << std::get(t)), 0)... }; +} +template +decltype(auto) operator<<(std::basic_ostream& os, const std::tuple& t) { + os << "{"; + print_tuple_impl(os, t, std::index_sequence_for{}); + return os << "}"; +} +template ostream& operator<<(ostream& out, const vector& vec) { + for (auto&& i : vec) out << i << ' '; + return out; +} + +/* pops */ +#define poptop(q, ...) __AS_PROCEDURE(auto [__VA_ARGS__] = q.top(); q.pop();) +#define popback(q, ...) __AS_PROCEDURE(auto [__VA_ARGS__] = q.back(); q.pop_back();) +#define popfront(q, ...) __AS_PROCEDURE(auto [__VA_ARGS__] = q.front();q.pop_front();) + +/* math */ +constexpr inline int lg2(ll x) { return x == 0 ? -1 : sizeof(ll) * 8 - 1 - __builtin_clzll(x); } + +void __exgcd(ll a, ll b, ll& x, ll& y) { + if (b == 0) { + x = 1, y = 0; + return; + } + __exgcd(b, a % b, y, x); + y -= a / b * x; +} + +ll inverse(ll a, ll b) { + ll x, y; + __exgcd(a, b, x, y); + return mod(x, b); +} + +/* string algorithms */ +vector calc_next(string t) { // pi function of t + int n = (int)t.length(); + vector pi(n); + for (int i = 1; i < n; i++) { + int j = pi[i - 1]; + while (j > 0 && t[i] != t[j]) j = pi[j - 1]; + if (t[i] == t[j]) j++; + pi[i] = j; + } + return pi; +} +vector calc_z(string t) { // z function of t + int m = t.length(); + vector z; + z.push_back(m); + pair prev = {1, -1}; + for (int i = 1; i < m; ++i) { + if (z[i - prev.first] + i <= prev.second) { + z.push_back(z[i - prev.first]); + } else { + int j = max(i, prev.second + 1); + while (j < m && t[j] == t[j - i]) ++j; + z.push_back(j - i); + prev = {i, j - 1}; + } + } + return z; +} +vector kmp(string s, string t) { // find all t in s + string cur = t + '#' + s; + int sz1 = s.size(), sz2 = t.size(); + vector v; + vector lps = calc_next(cur); + for (int i = sz2 + 1; i <= sz1 + sz2; i++) { + if (lps[i] == sz2) v.push_back(i - 2 * sz2); + } + return v; +} +int period(string s) { // find the length of shortest recurring period + int n = s.length(); + auto z = calc_z(s); + for (int i = 1; i <= n / 2; ++i) { + if (n % i == 0 && z[i] == n - i) { + return i; + } + } + return n; +} +///////////////////////////////////////////////////////// +]] + diff --git a/lua/snippets/exgcd.lua b/lua/snippets/exgcd.lua new file mode 100644 index 0000000..06af022 --- /dev/null +++ b/lua/snippets/exgcd.lua @@ -0,0 +1,93 @@ +return [[ +namespace Exgcd { + template T abs(T x) { return x < 0 ? -x : x; } + + template + struct exgcd_solution_t { + T x, y, gcd; + }; + + template + struct diophantine_solution_t { + exgcd_solution_t x_min, y_min; + T range; + }; + + // solve `ax + by = gcd(a, b)` + template + optional> exgcd(T a, T b) { + if (a < 0 || b < 0 || a == 0 && b == 0) return nullopt; + T x, y, g; + function __exgcd = [&__exgcd, &x, &y, &g] (T a, T b) -> void { + if (b == 0) { + g = a, x = 1, y = 0; + } else { + __exgcd(b, a % b); + swap(x, y); + y -= a / b * x; + } + }; + __exgcd(a, b); + return {{ x, y, g }}; + }; + + template + optional inverse(T a, T b) { + auto raw = exgcd(a, b); + if (raw == nullopt || raw.value().gcd != 1) { + return nullopt; + } else { + return mod(raw.value().x, b); + } + } + + // solve { x = a_i (mod n_i) } if n_i's are coprime + template + optional crt(const vector>& equations) { + T prod = 1; + for (auto&& [a, n] : equations) { + prod *= n; + } + T res = 0; + for (auto&& [a, n] : equations) { + T m = prod / n; + auto m_rev = inverse(m, n); + if (m_rev == nullopt) return nullopt; + res = mod(res + a * mod(m * m_rev.value(), prod), prod); + } + return res; + } + + // find minimal non-negative integral solutions of `ax + by = c`. It's not guaranteed that the other variable is non-negative. + template + optional> diophantine(T a, T b, T c, bool force_positive = false) { + if (a < 0 || b < 0 || a == 0 && b == 0) return nullopt; + auto raw = exgcd(a, b).value(); + if (c % raw.gcd) { + return nullopt; + } else { + T x = raw.x * c / raw.gcd, y = raw.y * c / raw.gcd; + T kx = force_positive ? (x <= 0 ? (-x) * raw.gcd / b + 1 : 1 - (x + b / raw.gcd - 1) * raw.gcd / b) : (x <= 0 ? ((-x) + b / raw.gcd - 1) * raw.gcd / b : (- x * raw.gcd / b)); + T ky = force_positive ? (y <= 0 ? (- 1 - (-y) * raw.gcd / a) : (y + a / raw.gcd - 1) * raw.gcd / a - 1) : (y <= 0 ? (- ((-y) + a / raw.gcd - 1) * raw.gcd / a) : y * raw.gcd / a); + return {{ { x + b * kx / raw.gcd , y - a * kx / raw.gcd , raw.gcd }, { x + b * ky / raw.gcd , y - a * ky / raw.gcd, raw.gcd }, abs(kx - ky) + 1 }}; + } + } + + // find the minimal non-negative integral solution of `ax = b (mod n)` + template + optional congruential(T a, T b, T n) { + if (a == 0) { + if (b != 0) return nullopt; + return 0; + } + if (a < 0 && a != LLONG_MIN && b != LLONG_MIN) a = -a, b = -b; + auto sol = diophantine(a, n, b); + if (sol == nullopt) { + return nullopt; + } else { + return sol.value().x_min.x; + } + } +} + +]] diff --git a/lua/snippets/fhq-treap.lua b/lua/snippets/fhq-treap.lua new file mode 100644 index 0000000..80cd966 --- /dev/null +++ b/lua/snippets/fhq-treap.lua @@ -0,0 +1,176 @@ +return [[ +// @link https://www.acwing.com/file_system/file/content/whole/index/content/8807719/ +// Everything starts from 1 + +namespace treap_link { + template class prev { + public: + T operator()(const T& a) { + return a - 1; + } + }; + template class next { + public: + T operator()(const T& a) { + return a + 1; + } + }; +} + +template , + typename Prev = treap_link::prev, + typename Next = treap_link::next> +class treap { + +#define lson fhq[u].l +#define rson fhq[u].r +private: + using size_type = size_t; + using value_type = T; + using reference = value_type&; + using const_reference = const reference; + + struct Node { + int key; + size_type l, r, size; + value_type val; + }; + Compare __compare; + Prev __prev; + Next __next; + vector fhq; + size_type cnt, root; + size_type x, y, z; + size_type _size; + + void pushup(size_type u) { + fhq[u].size = fhq[lson].size + fhq[rson].size + 1; + } + + size_type node(value_type val) { + if (cnt + 1 >= fhq.size()) { + fhq.push_back({}); + } + fhq[++cnt].val = val; + fhq[cnt].key = rand(); + fhq[cnt].size = 1; + return cnt; + } + + void split(size_type u, value_type val, size_type &x, size_type &y) { + if (!u) x = y = 0; + else { + if (!__compare(val, fhq[u].val)) x = u, split(rson, val, rson, y); + else y = u, split(lson, val, x, lson); + pushup(u); + } + } + + size_type merge(size_type x, size_type y) { + if (!x || !y) return x + y; + if (fhq[x].key <= fhq[y].key) { + fhq[x].r = merge(fhq[x].r, y); + pushup(x); + return x; + } else { + fhq[y].l = merge(x, fhq[y].l); + pushup(y); + return y; + } + } + + value_type askNum(size_type u, size_type rank) { + if (fhq[lson].size + 1 == rank) return fhq[u].val; + if (fhq[lson].size >= rank) return askNum(lson, rank); + else return askNum(rson, rank - fhq[lson].size - 1); + } + +public: + treap(Compare __compare = std::less(), + Prev __prev = treap_link::prev(), + Next __next = treap_link::next()) : + fhq(1), cnt(0), root(0), _size(0), + __compare(__compare), __prev(__prev), __next(__next) {} + treap(size_type n, Compare __compare = std::less(), + Prev __prev = treap_link::prev(), + Next __next = treap_link::next()) : + fhq(1), cnt(0), root(0), _size(0) { + fhq.reserve(n + 1); + } + + template> + treap(_InputIterator __first, _InputIterator __last) + : fhq(1), cnt(0), root(0), _size(0) { + __try { + for (; __first != __last; ++__first) { + insert(*__first); + } + } __catch(...) { + clear(); + __throw_exception_again; + } + } + + void clear() { + _size = root = cnt = 0; + fill(fhq.begin(), fhq.end(), Node()); + } + + void insert(value_type val) { + ++_size; + split(root, val, x, y); + root = merge(merge(x, node(val)), y); + } + + void remove(value_type val) { + assert(contains(val)); + --_size; + split(root, val, x, z); + split(x, __prev(val), x, y); + y = merge(fhq[y].l, fhq[y].r); + root = merge(merge(x, y), z); + } + + size_type index_of(value_type val) { + split(root, __prev(val), x, y); + size_type res = fhq[x].size + 1; + root = merge(x, y); + return res; + } + + value_type at(size_type rank) { + assert(rank > 0 && rank <= _size); + return askNum(root, rank); + } + + value_type prev_element(value_type val) { + split(root, __prev(val), x, y); + size_type u = x; + while (rson) u = rson; + root = merge(x, y); + return fhq[u].val; + } + + value_type next_element(value_type val) { + split(root, val, x, y); + size_type u = y; + while (lson) u = lson; + root = merge(x, y); + return fhq[u].val; + } + + bool contains(value_type val) { + size_type idx = index_of(val); + return idx <= _size && at(idx) == val; + } + + size_type size() { + return _size; + } + +#undef lson +#undef rson +}; + +]] diff --git a/lua/snippets/hash-deque.lua b/lua/snippets/hash-deque.lua new file mode 100644 index 0000000..355ed62 --- /dev/null +++ b/lua/snippets/hash-deque.lua @@ -0,0 +1,55 @@ +return [[ +static vector power1, power2; +static const ll b = rd(); +static const ll INV1 = inverse(b, MDL1); +static const ll INV2 = inverse(b, MDL2); +template > +struct hash_deque { + using hash_type = pll; + ll hash1, hash2; + _Sequence seq; + size_t size() { + return seq.size(); + } + void push_back(const _Tp& x) { + hash1 = mod(mod(hash1 * b, MDL1) + mod(x, MDL1), MDL1); + hash2 = mod(mod(hash2 * b, MDL2) + mod(x, MDL2), MDL2); + seq.push_back(x); + } + void push_front(const _Tp& x) { + size_t length = size(); + hash1 = mod(hash1 + mod(mod(x, MDL1) * power1[length], MDL1), MDL1); + hash2 = mod(hash2 + mod(mod(x, MDL2) * power2[length], MDL2), MDL2); + seq.push_front(x); + } + void pop_back() { + _Tp e = seq.back(); seq.pop_back(); + hash1 = mod(mod(hash1 - mod(e, MDL1), MDL1) * INV1, MDL1); + hash2 = mod(mod(hash2 - mod(e, MDL2), MDL2) * INV2, MDL2); + } + void pop_front() { + _Tp e = seq.front(); seq.pop_front(); + int length = seq.size(); + hash1 = mod(hash1 - mod(e * power1[length], MDL1), MDL1); + hash2 = mod(hash2 - mod(e * power2[length], MDL2), MDL2); + } + hash_type hash() { + return {hash1, hash2}; + } + void clear() { + hash1 = hash2 = 0; + seq.clear(); + } + hash_deque(size_t maxn) { + clear(); + int c1 = 1, c2 = 1; + for (int i = power1.size(); i < maxn; ++i) { + power1.push_back(c1); + power2.push_back(c2); + c1 = mod(c1 * b, MDL1); + c2 = mod(c2 * b, MDL2); + } + } +}; + +]] diff --git a/lua/snippets/hash-vec.lua b/lua/snippets/hash-vec.lua new file mode 100644 index 0000000..b14d17e --- /dev/null +++ b/lua/snippets/hash-vec.lua @@ -0,0 +1,72 @@ +return [[ +static vector> power1; +static vector> power2; +static const ll b = rd(); +template +struct hash_vec { + using hash_type = pll; + MLL hash1; + MLL hash2; + vector<_Tp> seq; + size_t size() { + return seq.size(); + } + void push_back(const _Tp& x) { + hash1 = hash1 * b + x; + hash2 = hash2 * b + x; + seq.push_back(x); + } + void push_front(const _Tp& x) { + size_t length = size(); + hash1 += x * power1[length]; + hash2 += x * power2[length]; + seq.push_front(x); + } + void pop_back() { + _Tp e = seq.back(); seq.pop_back(); + hash1 = (hash1 - e) / b; + hash2 = (hash2 - e) / b; + } + void pop_front() { + _Tp e = seq.front(); seq.pop_front(); + int length = seq.size(); + hash1 -= e * power1[length]; + hash2 -= e * power2[length]; + } + void set(size_t pos, const _Tp& value) { + int length = seq.size(); + int old_value = seq[pos]; + hash1 += (value - old_value) * power1[length - 1 - pos]; + hash2 += (value - old_value) * power2[length - 1 - pos]; + seq[pos] = value; + } + const _Tp& operator[](size_t pos) { + return seq[pos]; + } + hash_type hash() { + return {hash1.val, hash2.val}; + } + void clear() { + hash1 = 0; + hash2 = 0; + seq.clear(); + } + hash_vec(size_t maxn) { + clear(); + MLL c1 = 1; + MLL c2 = 1; + for (int i = power1.size(); i < maxn; ++i) { + power1.push_back(c1); + power2.push_back(c2); + c1 *= b; + c2 *= b; + } + } + hash_vec(size_t maxn, const _Tp& init_value) : hash_vec(maxn) { + for (size_t i = 0; i != maxn; ++i) { + push_back(init_value); + } + } +}; + +]] diff --git a/lua/snippets/init.lua b/lua/snippets/init.lua new file mode 100644 index 0000000..9a74066 --- /dev/null +++ b/lua/snippets/init.lua @@ -0,0 +1,181 @@ +local ls = require('luasnip') +local snip = ls.snippet +local text = ls.text_node + + +local function lines(str) + local result = {} + for line in str:gmatch '[^\n]+' do + table.insert(result, line) + end + return result +end + +local cpp_include = require('snippets.cpp-include') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'include', + namr = 'cpp-include', + dscr = 'Useful Macros', + },{ + text(lines(cpp_include)) + }) + } +}) + +local segtree_generic = require('snippets.segtree-generic') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'segtree', + namr = 'segtree_generic', + dscr = 'Segment Tree with Lazy Propagation', + },{ + text(lines(segtree_generic)) + }) + } +}) + +local fhq_treap = require('snippets.fhq-treap') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'treap', + namr = 'fhq_treap', + dscr = 'FHQ Treap', + },{ + text(lines(fhq_treap)) + }) + } +}) + +local fhq_treap = require('snippets.fhq-treap') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'treap', + namr = 'fhq_treap', + dscr = 'FHQ Treap', + },{ + text(lines(fhq_treap)) + }) + } +}) + +local bit = require('snippets.bit') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'bit', + namr = 'bit', + dscr = 'Bit-Indexed Tree', + },{ + text(lines(bit)) + }) + } +}) + +local quick_union = require('snippets.quick-union') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'quick_union', + namr = 'quick_union', + dscr = 'Union Find', + },{ + text(lines(quick_union)) + }) + } +}) + +local sparse_table = require('snippets.sparse-table') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'sparse_table', + namr = 'sparse_table', + dscr = 'Sparse Table', + },{ + text(lines(sparse_table)) + }) + } +}) + +local hash_deque = require('snippets.hash-deque') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'hash_deque', + namr = 'hash_deque', + dscr = 'Hashable Deque', + },{ + text(lines(hash_deque)) + }) + } +}) + +local hash_vec = require('snippets.hash-vec') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'hash_vec', + namr = 'hash_vec', + dscr = 'Hashable Vector', + },{ + text(lines(hash_vec)) + }) + } +}) + +local exgcd = require('snippets.exgcd') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'exgcd', + namr = 'exgcd', + dscr = 'Extended GCD and Related', + },{ + text(lines(exgcd)) + }) + } +}) + +local lpf = require('snippets.lpf') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'lpf', + namr = 'lpf', + dscr = 'Least Prime Factor', + },{ + text(lines(lpf)) + }) + } +}) + +local pollard_rho = require('snippets.pollard-rho') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'pollard_rho', + namr = 'pollard_rho', + dscr = 'Pollard-Rho', + },{ + text(lines(pollard_rho)) + }) + } +}) + +local tarjan = require('snippets.tarjan') +ls.add_snippets(nil, { + cpp = { + snip({ + trig = 'tarjan', + namr = 'tarjan', + dscr = 'Tarjan and Related', + },{ + text(lines(tarjan)) + }) + } +}) diff --git a/lua/snippets/lpf.lua b/lua/snippets/lpf.lua new file mode 100644 index 0000000..d3ba2e1 --- /dev/null +++ b/lua/snippets/lpf.lua @@ -0,0 +1,22 @@ +return [[ +constexpr int N = 1e7 + 10; + +int lpf[N]; + +void era(int n) { + lpf[0] = lpf[1] = -1; + for (int i = 2; i <= n; ++i) lpf[i] = i; + for (int i = 2; i <= n; ++i) { + if (lpf[i] == i) { + if ((ll)i * i > n) continue; + for (int j = i * i; j <= n; j += i) { + if (lpf[j] == j) { + lpf[j] = i; + } + } + } + } +} + + +]] diff --git a/lua/snippets/pollard-rho.lua b/lua/snippets/pollard-rho.lua new file mode 100644 index 0000000..e53e04e --- /dev/null +++ b/lua/snippets/pollard-rho.lua @@ -0,0 +1,91 @@ +return [[ +vector> decompose(ll x) { + vector> res; + for (int i = 2; i * i <= x; i++) { + if (x % i == 0) { + int cnt = 0; + ll pw = 1; + while (x % i == 0) ++cnt, x /= i, pw *= i; + res.emplace_back(i, cnt, pw); + } + } + if (x != 1) { + res.emplace_back(x, 1, x); + } + return res; +} + +struct pollard_rho { + ll max_factor; + + pollard_rho() : max_factor(0) { srand(time(NULL)); } + + ll quick_pow(ll x, ll p, ll mod) { + ll ans = 1; + while (p) { + if (p & 1) ans = (__int128)ans * x % mod; + x = (__int128)x * x % mod; + p >>= 1; + } + return ans; + } + + bool Miller_Rabin(ll p) { + if (p < 2) return 0; + if (p == 2) return 1; + if (p == 3) return 1; + ll d = p - 1, r = 0; + while (!(d & 1)) ++r, d >>= 1; + for (ll k = 0; k < 10; ++k) { + ll a = rand() % (p - 2) + 2; + ll x = quick_pow(a, d, p); + if (x == 1 || x == p - 1) continue; + for (int i = 0; i < r - 1; ++i) { + x = (__int128)x * x % p; + if (x == p - 1) break; + } + if (x != p - 1) return 0; + } + return 1; + } + + ll Pollard_Rho(ll x) { + ll s = 0, t = 0; + ll c = (ll)rand() % (x - 1) + 1; + int step = 0, goal = 1; + ll val = 1; + for (goal = 1;; goal *= 2, s = t, val = 1) { + for (step = 1; step <= goal; ++step) { + t = ((__int128)t * t + c) % x; + val = (__int128)val * abs(t - s) % x; + if ((step % 127) == 0) { + ll d = gcd(val, x); + if (d > 1) return d; + } + } + ll d = gcd(val, x); + if (d > 1) return d; + } + } + + void fac(ll x) { + if (x <= max_factor || x < 2) return; + if (Miller_Rabin(x)) { + max_factor = max(max_factor, x); + return; + } + ll p = x; + while (p >= x) p = Pollard_Rho(x); + while ((x % p) == 0) x /= p; + fac(x), fac(p); + } + + // find greatest prime factor of `x` + ll solve(ll x) { + max_factor = 0; + fac(x); + return max_factor; + } +}; + +]] diff --git a/lua/snippets/quick-union.lua b/lua/snippets/quick-union.lua new file mode 100644 index 0000000..d145be1 --- /dev/null +++ b/lua/snippets/quick-union.lua @@ -0,0 +1,31 @@ +return [[ +class quick_union { +private: + vector c, sz; +public: + quick_union(size_t n) : c(n), sz(n) { + iota(c.begin(), c.end(), 0); + sz.assign(n, 1); + } + + size_t query(size_t i) { + if (c[i] != i) c[i] = query(c[i]); + return c[i]; + } + + void merge(size_t i, size_t j) { + if (connected(i, j)) return; + sz[query(j)] += sz[query(i)]; + c[query(i)] = query(j); + } + + bool connected(size_t i, size_t j) { + return query(i) == query(j); + } + + size_t query_size(size_t i) { + return sz[query(i)]; + } +}; + +]] diff --git a/lua/snippets/segtree-generic.lua b/lua/snippets/segtree-generic.lua new file mode 100644 index 0000000..35f48c9 --- /dev/null +++ b/lua/snippets/segtree-generic.lua @@ -0,0 +1,128 @@ +return [[ + +template> class segtree { +private: + using size_type = uint64_t; + using info_type = Addable_Info_t; + using tag_type = Tag_t; + size_type _max; + vector d; + vector b; + + void pull(size_type p) { + d[p] = d[p * 2] + d[p * 2 + 1]; + } + + void push(size_type p, size_type left_len, size_type right_len) { + d[p * 2].apply(b[p], left_len), d[p * 2 + 1].apply(b[p], right_len); + b[p * 2].apply(b[p]), b[p * 2 + 1].apply(b[p]); + b[p] = tag_type(); + } + + void set(size_type s, size_type t, size_type p, size_type x, const info_type& c) { + if (s == t) { + d[p] = c; + return; + } + size_type m = s + (t - s >> 1); + if (s != t) push(p, m - s + 1, t - m); + if (x <= m) set(s, m, p * 2, x, c); + else set(m + 1, t, p * 2 + 1, x, c); + d[p] = d[p * 2] + d[p * 2 + 1]; + } + + void range_apply(size_type s, size_type t, size_type p, size_type l, size_type r, const tag_type& c) { + if (l <= s && t <= r) { + d[p].apply(c, t - s + 1); + b[p].apply(c); + return; + } + size_type m = s + (t - s >> 1); + push(p, m - s + 1, t - m); + if (l <= m) range_apply(s, m, p * 2, l, r, c); + if (r > m) range_apply(m + 1, t, p * 2 + 1, l, r, c); + pull(p); + } + + info_type range_query(size_type s, size_type t, size_type p, size_type l, size_type r) { + if (l <= s && t <= r) { + return d[p]; + } + size_type m = s + (t - s >> 1); + info_type res = {}; + push(p, m - s + 1, t - m); + if (l <= m) res = res + range_query(s, m, p * 2, l, r); + if (r > m) res = res + range_query(m + 1, t, p * 2 + 1, l, r); + return res; + } + + void build(const Sequence& a, size_type s, size_type t, size_type p) { + if (s == t) { + d[p] = a[s]; + return; + } + int m = s + (t - s >> 1); + build(a, s, m, p * 2); + build(a, m + 1, t, p * 2 + 1); + pull(p); + } +public: + segtree(size_type __max) : d(4 * __max), b(4 * __max), _max(__max - 1) {} + segtree(const Sequence& a) : segtree(a.size()) { + build(a, {}, _max, 1); + } + + void set(size_type i, const info_type& c) { + set({}, _max, 1, i, c); + } + + void range_apply(size_type l, size_type r, const tag_type& c) { + range_apply({}, _max, 1, l, r, c); + } + + void apply(size_type i, const tag_type& c) { + range_apply(i, i, c); + } + + info_type range_query(size_type l, size_type r) { + return range_query({}, _max, 1, l, r); + } + + info_type query(size_type i) { + return range_query(i, i); + } + + Sequence serialize() { + Sequence res = {}; + for (size_type i = 0; i <= _max; ++i) { + res.push_back(query(i)); + } + return res; + } + + const vector& get_d() { + return d; + } +}; + +struct Tag { + ll val = -1; + void apply(const Tag& rhs) { + if (rhs.val != -1) + val = rhs.val; + } +}; + +struct Info { + ll val = 0; + void apply(const Tag& rhs, size_t len) { + if (rhs.val != -1) + val = rhs.val * len; + } +}; + +Info operator+(const Info &a, const Info &b) { + return {a.val + b.val}; +} + +]] diff --git a/lua/snippets/sparse-table.lua b/lua/snippets/sparse-table.lua new file mode 100644 index 0000000..1684f14 --- /dev/null +++ b/lua/snippets/sparse-table.lua @@ -0,0 +1,25 @@ +return [[ +template> struct sparse_table { + _Op op; + vector> st; + template + sparse_table(ReverseIterator __first, ReverseIterator __last, _Op&& __operation) { + op = __operation; + int n = distance(__first, __last); + st = vector>(n, vector<_Tp>(int(log2(n) + 1))); + int i = n - 1; + for (auto it = __first; it != __last; ++it) { + st[i][0] = *it; + for (int j = 1; i + (1 << j) <= n; ++j) { + st[i][j] = op(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); + } + i -= 1; + } + } + _Tp query(size_t __start, size_t __end) { + int s = lg2(__end - __start + 1); + return op(st[__start][s], st[__end - (1 << s) + 1][s]); + } +}; + +]] diff --git a/lua/snippets/tarjan.lua b/lua/snippets/tarjan.lua new file mode 100644 index 0000000..2f856b6 --- /dev/null +++ b/lua/snippets/tarjan.lua @@ -0,0 +1,71 @@ +return [=[ +namespace tarjan { + // Returns the mapping between vertices and their affiliated sccs. + vector scc(const vector>& ch) { + int n = ch.size(); + int cnt = 0, scn = 0; + vector dfn(n), low(n), vis(n), st; + vector br(n); + auto tarjan = [&] (auto tarjan, int v) -> void { + dfn[v]=low[v]=++cnt; + st.push_back(v); + vis[v]=1; + for(const auto&u:ch[v]) + if(!dfn[u]) tarjan(tarjan, u),low[v]=min(low[v],low[u]); + else if(vis[u])low[v]=min(low[v],dfn[u]); + if(dfn[v]==low[v]){ + ++scn; + int u; + do u=st.back(), st.pop_back(),vis[u]=0,br[u]=scn; while(u!=v); + } + }; + for (int i = 0; i < n; ++i) { + if (!dfn[i]) { + tarjan(tarjan, i); + } + } + return br; + } + + // This method can eliminate redundant edges or self-loops + vector> build_scc(const vector>& ch) { + int n = ch.size(); + auto br = scc(ch); + int cnt = *max_element(br.begin(), br.end()); + vector> rb(cnt + 1); + for (int i = 0; i < n; ++i) { + for (auto&& u : ch[i]) { + if (br[i] != br[u]) rb[br[i]].emplace(br[u]); + } + } + vector> res(cnt + 1); + for (int i = 1; i <= cnt; ++i) { + res[i] = vector(rb[i].begin(), rb[i].end()); + } + return res; + } + + // This method can eliminate redundant edges or self-loops + // return form: (scc size, children of scc) + vector>> build_scc_with_size(const vector>& ch) { + int n = ch.size(); + auto br = scc(ch); + int cnt = *max_element(br.begin(), br.end()); + vector> rb(cnt + 1); + for (int i = 0; i < n; ++i) { + for (auto&& u : ch[i]) { + if (br[i] != br[u]) rb[br[i]].emplace(br[u]); + } + } + vector>> res(cnt + 1); + for (int i = 1; i <= cnt; ++i) { + res[i].second = vector(rb[i].begin(), rb[i].end()); + } + for (int i = 1; i <= n; ++i) { + res[br[i]].first += 1; + } + return res; + } +} + +]=]