< pitPさんのAI生成コード置き場

cpp.json + template.cpp(AHC)

投稿者pitP
言語C++23
更新日時 (JST)2026-10-14 20:58:14
サイズ190,600 Byte
参照URL

日時はサーバーが記録したものです。更新すると更新日時が変わるので、不都合がある場合は新しく投稿してください。

テキストで開く
{
	// Place your snippets for cpp here. Each snippet is defined under a snippet name and has a prefix, body and 
	// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
	// same ids are connected.
	// Example:
	// "Print to console": {
	// 	"prefix": "log",
	// 	"body": [
	// 		"console.log('$1');",
	// 		"$2"
	// 	],
	// 	"description": "Log output to console"
	// }
	"template": {
		"prefix": "atcoder_cpp_",
		"body": [
		"#include <bits/stdc++.h>",
		"#include <atcoder/all>",
		"using namespace std;",
		"using namespace atcoder;",
		"istream &operator>>(istream &is, modint &a) { long long v; is >> v; a = v; return is; }",
		"ostream &operator<<(ostream &os, const modint &a) { return os << a.val(); }",
		"istream &operator>>(istream &is, modint998244353 &a) { long long v; is >> v; a = v; return is; }",
		"ostream &operator<<(ostream &os, const modint998244353 &a) { return os << a.val(); }",
		"istream &operator>>(istream &is, modint1000000007 &a) { long long v; is >> v; a = v; return is; }",
		"ostream &operator<<(ostream &os, const modint1000000007 &a) { return os << a.val(); } ",
		"",
		"typedef long long ll;",
		"typedef vector<vector<int>> Graph;",
		"typedef pair<int, int> pii;",
		"typedef pair<ll, ll> pll;",
		"#define FOR(i,l,r) for (int i = l;i < (int)(r); i++)",
		"#define rep(i,n) for (int i = 0;i < (int)(n); i++)",
		"#define all(x) x.begin(), x.end()",
		"#define rall(x) x.rbegin(), x.rend()",
		"#define my_sort(x) sort(x.begin(), x.end())",
		"#define my_max(x) *max_element(all(x))",
		"#define my_min(x) *min_element(all(x))",
		"template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }",
		"template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }",
		"const int INF = (1<<30) - 1;",
		"const ll LINF = (1LL<<62) - 1;",
		"const int MOD = 998244353;",
		"const int MOD2 = 1e9+7;",
		"const double PI = acos(-1);",
		"vector<int> di = {1,0,-1,0};",
		"vector<int> dj = {0,1,0,-1};",
		"",
		"#ifdef LOCAL",
		"#  include <debug_print.hpp>",
		"#  define debug(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__)",
		"#else",
		"#  define debug(...) (static_cast<void>(0))",
		"#endif",
		"",
		"int main(){",
		"    cin.tie(0);",
		"    ios_base::sync_with_stdio(false);",
		"}",
		""
		],
		"description": "template"
	},
	"codeforces": {
		"prefix": "atcoder_cpp_codeforces",
		"body": [
		"#include <bits/stdc++.h>",
		"using namespace std;",
		"",
		"typedef long long ll;",
		"typedef vector<vector<int>> Graph;",
		"typedef pair<int, int> pii;",
		"typedef pair<ll, ll> pll;",
		"#define FOR(i,l,r) for (int i = l;i < (int)(r); i++)",
		"#define rep(i,n) for (int i = 0;i < (int)(n); i++)",
		"#define all(x) x.begin(), x.end()",
		"#define rall(x) x.rbegin(), x.rend()",
		"#define my_sort(x) sort(x.begin(), x.end())",
		"#define my_max(x) *max_element(all(x))",
		"#define my_min(x) *min_element(all(x))",
		"template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }",
		"template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }",
		"const int INF = (1<<30) - 1;",
		"const ll LINF = (1LL<<62) - 1;",
		"const int MOD = 998244353;",
		"const int MOD2 = 1e9+7;",
		"const double PI = acos(-1);",
		"vector<int> di = {1,0,-1,0};",
		"vector<int> dj = {0,1,0,-1};",
		"",
		"#ifdef LOCAL",
		"#  include <debug_print.hpp>",
		"#  define debug(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__)",
		"#else",
		"#  define debug(...) (static_cast<void>(0))",
		"#endif",
		"",
		"void solve(){",
		"}",
		"",
		"int main(){",
		"    cin.tie(0);",
		"    ios_base::sync_with_stdio(false);",
		"    int t = 1; ",
		"    cin >> t;",
		"    while(t--) solve();",
		"}"
		],
		"description": "codeforces"
	},
	//
	//data structure
	//
	"sortedset": {
	"prefix": "atcoder_data_sortedset",
	"body": [
		"template<typename T>",
		"struct SortedSet{",
		"    const int BUCKET_RATIO = 50;",
		"    const int SPLIT_RATIO = 170;",
		"    vector<vector<T>> a;",
		"    int sz = 0;",
		"",
		"    SortedSet(){}",
		"    SortedSet(const vector<T> &vec){",
		"        vector<T> dat = vec;",
		"        sort(dat.begin(), dat.end());",
		"        dat.erase(unique(dat.begin(), dat.end()), dat.end());",
		"",
		"        int n = sz = dat.size();",
		"        int num_bucket = (int)ceil(sqrt((double)n / (double)BUCKET_RATIO));",
		"        a.resize(num_bucket);",
		"        for(int i = 0; i < num_bucket; i++){",
		"            a[i] = vector<T>(dat.begin() + n * i / num_bucket, dat.begin() + n * (i + 1) / num_bucket);",
		"        }",
		"    }",
		"",
		"    bool operator==(const SortedSet& other) {",
		"        return this->a == other.a;",
		"    }",
		"",
		"    size_t size() { return sz; }",
		"",
		"    friend ostream& operator<<(ostream& os, const SortedSet& st) {",
		"        os << \"{ \";",
		"        for(const auto&vec : st.a){",
		"            for(const auto& v : vec){",
		"                os << v << \" \";",
		"            }",
		"        }",
		"        os << \"}\";",
		"        return os;",
		"    }",
		"",
		"    pair<int, int> _position(const T &x){",
		"        int as = a.size();",
		"        for(int i = 0; i < as; i++){",
		"            if(x <= a[i].back()) {",
		"                return make_pair(i, lower_bound(a[i].begin(), a[i].end(), x) - a[i].begin());",
		"            }",
		"        }",
		"        return make_pair(as - 1, lower_bound(a[as - 1].begin(), a[as - 1].end(), x) - a[as - 1].begin());",
		"    }",
		"",
		"    int count(const T &x){ return this->index_right(x) - this->index(x); }",
		"",
		"    bool add(const T &x){",
		"        if(sz == 0){",
		"            a = {{x}};",
		"            sz = 1;",
		"            return true;",
		"        }",
		"        auto [b, i] = _position(x);",
		"        if(i != (int)a[b].size() && a[b][i] == x) return false;",
		"        a[b].insert(a[b].begin() + i, x);",
		"        sz++;",
		"        if((int)a[b].size() > (int)a.size() * SPLIT_RATIO){",
		"            int mid = (int)a[b].size() >> 1;",
		"            vector<T> head(a[b].begin(), a[b].begin() + mid), tail(a[b].begin() + mid, a[b].end());",
		"            a.erase(a.begin() + b);",
		"            a.insert(a.begin() + b, tail);",
		"            a.insert(a.begin() + b, head);",
		"        }",
		"        return true;",
		"    }",
		"",
		"    T _pop(int b, int i){",
		"        T ans = a[b][i];",
		"        a[b].erase(a[b].begin() + i);",
		"        sz--;",
		"        if((int)a[b].size() == 0) a.erase(a.begin() + b);",
		"        return ans;",
		"    }",
		"    ",
		"    bool discard(const T &x){",
		"        if(sz == 0) return false;",
		"        auto [b, i] = _position(x);",
		"        if(i == (int)a[b].size() || a[b][i] != x) return false;",
		"        _pop(b, i);",
		"        return true;",
		"    }",
		"",
		"    optional<T> lt(const T &x){",
		"        for(int b = (int)a.size() - 1; b >= 0; b--){",
		"            if(a[b][0] < x){",
		"                int l = lower_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"                return a[b][l - 1];",
		"            }",
		"        }",
		"        return nullopt;",
		"    }",
		"",
		"    optional<T> le(const T &x){",
		"        for(int b = (int)a.size() - 1; b >= 0; b--){",
		"            if(a[b][0] <= x){",
		"                int r = upper_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"                return a[b][r - 1];",
		"            }",
		"        }",
		"        return nullopt;",
		"    }",
		"",
		"    optional<T> gt(const T &x){",
		"        for(int b = 0; b < (int)a.size(); b++){",
		"            if(a[b].back() > x){",
		"                int r = upper_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"                return a[b][r];",
		"            }",
		"        }",
		"        return nullopt;",
		"    }",
		"",
		"    optional<T> ge(const T &x){",
		"        for(int b = 0; b < (int)a.size(); b++){",
		"            if(a[b].back() >= x){",
		"                int l = lower_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"                return a[b][l];",
		"            }",
		"        }",
		"        return nullopt;",
		"    }",
		"",
		"    const T& operator[](int i) const {",
		"        if(i < 0){",
		"            assert(~i < sz);",
		"            for(int b = (int)a.size() - 1; b >= 0; b--){",
		"                i += (int)a[b].size();",
		"                if (i >= 0) return a[b][i];",
		"            }",
		"        }",
		"        else{",
		"            assert(i < sz);",
		"            for(int b = 0; b < (int)a.size(); b++){",
		"                if(i < (int)a[b].size()) return a[b][i];",
		"                i -= (int)a[b].size();",
		"            }",
		"        }",
		"    }",
		"",
		"    T pop(int i){",
		"        if(i < 0){",
		"            assert(~i < sz);",
		"            for(int b = (int)a.size() - 1; b >= 0; b--){",
		"                i += (int)a[b].size();",
		"                if (i >= 0) return _pop(b, i);",
		"            }",
		"        }",
		"        else{",
		"            assert(i < sz);",
		"            for(int b = 0; b < (int)a.size(); b++){",
		"                if(i < (int)a[b].size()) return _pop(b, i);",
		"                i -= (int)a[b].size();",
		"            }",
		"        }",
		"    }",
		"",
		"    int index(const T &x){",
		"        int ans = 0;",
		"        for(int b = 0; b < (int)a.size(); b++){",
		"            if(a[b].back() >= x){",
		"                return ans + lower_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"            }",
		"            ans += (int)a[b].size();",
		"        }",
		"        return ans;",
		"    }",
		"",
		"    int index_right(const T &x){",
		"        int ans = 0;",
		"        for(int b = 0; b < (int)a.size(); b++){",
		"            if(a[b].back() > x){",
		"                return ans + upper_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"            }",
		"            ans += (int)a[b].size();",
		"        }",
		"        return ans;",
		"    }",
		"};",
		"",
		"template<typename T>",
		"struct SortedMultiSet{",
		"    const int BUCKET_RATIO = 50;",
		"    const int SPLIT_RATIO = 170;",
		"    vector<vector<T>> a;",
		"    int sz = 0;",
		"",
		"    SortedMultiSet(){}",
		"    SortedMultiSet(const vector<T> &vec){",
		"        vector<T> dat = vec;",
		"        sort(dat.begin(), dat.end());",
		"",
		"        int n = sz = dat.size();",
		"        int num_bucket = (int)ceil(sqrt((double)n / (double)BUCKET_RATIO));",
		"        a.resize(num_bucket);",
		"        for(int i = 0; i < num_bucket; i++){",
		"            a[i] = vector<T>(dat.begin() + n * i / num_bucket, dat.begin() + n * (i + 1) / num_bucket);",
		"        }",
		"    }",
		"",
		"    bool operator==(const SortedMultiSet& other) {",
		"        return this->a == other.a;",
		"    }",
		"",
		"    size_t size() { return sz; }",
		"",
		"    friend ostream& operator<<(ostream& os, const SortedMultiSet& st) {",
		"        os << \"{ \";",
		"        for(const auto&vec : st.a){",
		"            for(const auto& v : vec){",
		"                os << v << \" \";",
		"            }",
		"        }",
		"        os << \"}\";",
		"        return os;",
		"    }",
		"",
		"    pair<int, int> _position(const T &x){",
		"        int as = a.size();",
		"        for(int i = 0; i < as; i++){",
		"            if(x <= a[i].back()) {",
		"                return make_pair(i, lower_bound(a[i].begin(), a[i].end(), x) - a[i].begin());",
		"            }",
		"        }",
		"        return make_pair(as - 1, lower_bound(a[as - 1].begin(), a[as - 1].end(), x) - a[as - 1].begin());",
		"    }",
		"",
		"    int count(const T &x) { return this->index_right(x) - this->index(x); }",
		"",
		"    void add(const T &x){",
		"        if(sz == 0){",
		"            a = {{x}};",
		"            sz = 1;",
		"            return;",
		"        }",
		"        auto [b, i] = _position(x);",
		"        a[b].insert(a[b].begin() + i, x);",
		"        sz++;",
		"        if((int)a[b].size() > (int)a.size() * SPLIT_RATIO){",
		"            int mid = (int)a[b].size() >> 1;",
		"            vector<T> head(a[b].begin(), a[b].begin() + mid), tail(a[b].begin() + mid, a[b].end());",
		"            a.erase(a.begin() + b);",
		"            a.insert(a.begin() + b, tail);",
		"            a.insert(a.begin() + b, head);",
		"        }",
		"    }",
		"",
		"    T _pop(int b, int i){",
		"        T ans = a[b][i];",
		"        a[b].erase(a[b].begin() + i);",
		"        sz--;",
		"        if((int)a[b].size() == 0) a.erase(a.begin() + b);",
		"        return ans;",
		"    }",
		"    ",
		"    bool discard(const T &x){",
		"        if(sz == 0) return false;",
		"        auto [b, i] = _position(x);",
		"        if(i == (int)a[b].size() || a[b][i] != x) return false;",
		"        _pop(b, i);",
		"        return true;",
		"    }",
		"",
		"    optional<T> lt(const T &x){",
		"        for(int b = (int)a.size() - 1; b >= 0; b--){",
		"            if(a[b][0] < x){",
		"                int l = lower_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"                return a[b][l - 1];",
		"            }",
		"        }",
		"        return nullopt;",
		"    }",
		"",
		"    optional<T> le(const T &x){",
		"        for(int b = (int)a.size() - 1; b >= 0; b--){",
		"            if(a[b][0] <= x){",
		"                int r = upper_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"                return a[b][r - 1];",
		"            }",
		"        }",
		"        return nullopt;",
		"    }",
		"",
		"    optional<T> gt(const T &x){",
		"        for(int b = 0; b < (int)a.size(); b++){",
		"            if(a[b].back() > x){",
		"                int r = upper_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"                return a[b][r];",
		"            }",
		"        }",
		"        return nullopt;",
		"    }",
		"",
		"    optional<T> ge(const T &x){",
		"        for(int b = 0; b < (int)a.size(); b++){",
		"            if(a[b].back() >= x){",
		"                int l = lower_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"                return a[b][l];",
		"            }",
		"        }",
		"        return nullopt;",
		"    }",
		"",
		"    const T& operator[](int i) const {",
		"        if(i < 0){",
		"            assert(~i < sz);",
		"            for(int b = (int)a.size() - 1; b >= 0; b--){",
		"                i += (int)a[b].size();",
		"                if (i >= 0) return a[b][i];",
		"            }",
		"        }",
		"        else{",
		"            assert(i < sz);",
		"            for(int b = 0; b < (int)a.size(); b++){",
		"                if(i < (int)a[b].size()) return a[b][i];",
		"                i -= (int)a[b].size();",
		"            }",
		"        }",
		"    }",
		"",
		"    T pop(int i){",
		"        if(i < 0){",
		"            assert(~i < sz);",
		"            for(int b = (int)a.size() - 1; b >= 0; b--){",
		"                i += (int)a[b].size();",
		"                if (i >= 0) return _pop(b, i);",
		"            }",
		"        }",
		"        else{",
		"            assert(i < sz);",
		"            for(int b = 0; b < (int)a.size(); b++){",
		"                if(i < (int)a[b].size()) return _pop(b, i);",
		"                i -= (int)a[b].size();",
		"            }",
		"        }",
		"    }",
		"",
		"    int index(const T &x){",
		"        int ans = 0;",
		"        for(int b = 0; b < (int)a.size(); b++){",
		"            if(a[b].back() >= x){",
		"                return ans + lower_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"            }",
		"            ans += (int)a[b].size();",
		"        }",
		"        return ans;",
		"    }",
		"",
		"    int index_right(const T &x){",
		"        int ans = 0;",
		"        for(int b = 0; b < (int)a.size(); b++){",
		"            if(a[b].back() > x){",
		"                return ans + upper_bound(a[b].begin(), a[b].end(), x) - a[b].begin();",
		"            }",
		"            ans += (int)a[b].size();",
		"        }",
		"        return ans;",
		"    }",
		"};",
		""
	],
	"description": "sortedset"
	},
	"removable_pq": {
	"prefix": "atcoder_data_removable_pq",
	"body": [
		"struct T{",
		"    int rate;",
		"    T(int _rate) : rate(_rate) {}",
		"",
		"    bool operator<(const T& x) const {",
		"        return this->rate < x.rate;",
		"    }",
		"",
		"    bool operator==(const T& x) const {",
		"        return this->rate == x.rate;",
		"    }",
		"};",
		"",
		"// you cannot erase element not in Q;",
		"// only greater",
		"template <typename T>",
		"struct removable_priority_queue{",
		"    priority_queue<T> Q, R;",
		"    removable_priority_queue(){}",
		"",
		"    void push(T x){ Q.push(x); }",
		"",
		"    void erase(T x){ R.push(x); }",
		"",
		"    T top(){",
		"        assert(!this->empty());",
		"        while(!R.empty() && R.top() == Q.top()){",
		"            R.pop();",
		"            Q.pop();",
		"        }",
		"        return Q.top();",
		"    };",
		"",
		"    int size(){ return Q.size() - R.size(); }",
		"",
		"    bool empty(){ return size() == 0; }",
		"};",
		""
	],
	"description": "removable_pq"
	},
	"RAQRSQ": {
	"prefix": "atcoder_data_RAQRSQ",
	"body": [
		"// verify : https://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=9516360#1",
		"template<typename T>",
		"struct RangeAddRangeSum{",
		"    int n;",
		"    atcoder::fenwick_tree<T> fw0, fw1;",
		"    RangeAddRangeSum(int n) : n(n) {",
		"        fw0 = atcoder::fenwick_tree<T>(n + 1);",
		"        fw1 = atcoder::fenwick_tree<T>(n + 1);",
		"    }",
		"",
		"    void add(int l, int r, T x){",
		"        fw0.add(l, -x * (T)(l - 1));",
		"        fw0.add(r, x * (T)(r - 1));",
		"        fw1.add(l, x);",
		"        fw1.add(r, -x);",
		"    }",
		"",
		"    void add(int i, T x) { return add(i, i + 1, x); }",
		"",
		"    // [0, i)",
		"    T _sum(int i) { return fw0.sum(0, i) + fw1.sum(0, i) * (T)(i - 1); }",
		"",
		"    // [l, r)",
		"    T sum(int l, int r) { return _sum(r) - _sum(l); }",
		"};",
		""
	],
	"description": "RAQRSQ"
	},
	"sparsetable2d": {
		"prefix": "atcoder_data_sparsetable2d",
		"body": [
		"template<class S, S(*op)(S, S), S(*e)()>",
		"struct SparseTable2d{",
		"    vector<vector<vector<vector<S>>>> table;",
		"    vector<int> bit_len; // bit_len[i] ... iを超えない最大の指数 (ex bit_len[6] = 2)",
		"    SparseTable2d(vector<vector<S>> &vec){",
		"        _build(vec);",
		"    }",
		"",
		"    void _build(vector<vector<S>> &vec){",
		"        int H = vec.size(), W = vec[0].size();",
		"        int logH = 0, logW = 0;",
		"        while((1 << logH) <= H) logH++;",
		"        while((1 << logW) <= W) logW++;",
		"",
		"        table.resize(logH, vector(logW, vector((1 << logH), vector<S>((1 << logW), e()))));",
		"        for(int i = 0; i < H; i++){",
		"            for(int j = 0; j < W; j++){",
		"                table[0][0][i][j] = vec[i][j];",
		"            }",
		"        }",
		"",
		"        for(int k = 0; k + 1 < logH; k++){",
		"            for(int i = 0; i + (1 << k) < (1 << logH); i++){",
		"                for(int j = 0; j < (1 << logW); j++){",
		"                    table[k + 1][0][i][j] = op(table[k][0][i][j], table[k][0][i + (1 << k)][j]);",
		"                }",
		"            }",
		"        }",
		"",
		"        for(int k = 0; k < logH; k++){",
		"            for(int l = 0; l + 1 < logW; l++){",
		"                for(int i = 0; i + (1 << k) < (1 << logH); i++){",
		"                    for(int j = 0; j + (1 << l) < (1 << logW); j++){",
		"                        table[k][l + 1][i][j] = op(table[k][l][i][j], table[k][l][i][j + (1 << l)]);",
		"                    }",
		"                }",
		"            }",
		"        }",
		"",
		"        bit_len.resize(max(H, W) + 1, 0);",
		"        for(int i = 2; i < (int)bit_len.size(); i++){",
		"            bit_len[i] = bit_len[i >> 1] + 1;",
		"        }",
		"    }",
		"",
		"    // [i0, i1) x [j0, j1)",
		"    S prod(int i0, int i1, int j0, int j1){",
		"        if(i0 >= i1 || j0 >= j1) return e();",
		"        int bi = bit_len[i1 - i0];",
		"        int bj = bit_len[j1 - j0];",
		"        return op(",
		"            op(table[bi][bj][i0][j0], table[bi][bj][i1 - (1 << bi)][j0]),",
		"            op(table[bi][bj][i0][j1 - (1 << bj)], table[bi][bj][i1 - (1 << bi)][j1 - (1 << bj)])",
		"        );",
		"    }",
		"};",
		""
		],
		"description": "sparsetable2d"
	},
	"sparsetable": {
		"prefix": "atcoder_data_sparsetable",
		"body": [
		"template <class S, S(*op)(S,S), S(*e)()>",
		"struct SparseTable {",
		"    vector<vector<S>> table;",
		"    vector<int> bit_len; // bit_len[i] ... iを超えない最大の指数 (ex bit_len[6] = 2)",
		"    SparseTable(vector<S> &vec){ ",
		"        _build(vec);",
		"    }",
		"",
		"    void _build(vector<S> &vec){",
		"        int N = vec.size();",
		"        int logN = 0;",
		"        while((1 << logN) <= N)logN++;",
		"",
		"        table.resize(logN, vector<S>(1 << logN, e()));",
		"        for(int i = 0; i < N; i++){",
		"            table[0][i] = vec[i];",
		"        }",
		"        for(int i = 0; i + 1 < logN; i++){",
		"            for(int j = 0; j + (1 << i) < (1 << logN); j++){",
		"                table[i + 1][j] = op(table[i][j], table[i][j + (1 << i)]);",
		"            }",
		"        }",
		"        bit_len.resize(N + 1, 0);",
		"        for(int i = 2; i < (int)bit_len.size(); i++){",
		"            bit_len[i] = bit_len[i >> 1] + 1;",
		"        }",
		"    }",
		"",
		"    S get(int p){",
		"        return table[0][p];",
		"    }",
		"",
		"    S prod(int l, int r){",
		"        if (r - l <= 0) return e();",
		"        int b = bit_len[r - l];",
		"        return op(table[b][l], table[b][r - (1 << b)]);",
		"    }",
		"};",
		""
		],
		"description": "sparsetable"
	},
	"rangetree": {
		"prefix": "atcoder_data_rangetree",
		"body": [
		"",
		"template <class S, S (*op)(S, S), S (*e)(), class CoordinateType> struct RangeTree {",
		"    using CT = CoordinateType;",
		"    using Point = pair<CT, CT>;",
		"    vector<Point> points;",
		"    vector<vector<Point>> yx;",
		"    vector<atcoder::segtree<S,op,e>> seg;",
		"    int n;",
		"",
		"    void _set(int idx, Point p, S val){",
		"        int i = lower_bound(yx[idx].begin(), yx[idx].end(), Point{p.second, p.first}) - yx[idx].begin();",
		"        seg[idx].set(i, val);",
		"    }",
		"    S _prod(int idx, CT yl, CT yr){",
		"        auto comp = [](const Point &lhs, const Point &rhs) {return lhs.first < rhs.first; };",
		"        int il = lower_bound(yx[idx].begin(), yx[idx].end(), Point{yl, yl}, comp) - yx[idx].begin();",
		"        int ir = lower_bound(yx[idx].begin(), yx[idx].end(), Point{yr, yr}, comp) - yx[idx].begin();",
		"        return seg[idx].prod(il, ir);",
		"    }",
		"",
		"    void add_point(CT x, CT y){",
		"        points.push_back(Point{x, y});",
		"    }",
		"",
		"    void build(){",
		"        sort(points.begin(), points.end());",
		"        points.erase(unique(points.begin(), points.end()), points.end());",
		"        n = points.size();",
		"",
		"        yx.resize(2 * n);",
		"        for(int i = 0; i < n; i++) yx[i + n] = { Point{points[i].second, points[i].first}};",
		"        for(int i = n - 1; i > 0; i--){",
		"            auto &lc = yx[2 * i];",
		"            auto &rc = yx[2 * i + 1];",
		"            merge(lc.begin(), lc.end(), rc.begin(), rc.end(), back_inserter(yx[i]));",
		"            yx[i].erase(unique(yx[i].begin(), yx[i].end()), yx[i].end());",
		"        }",
		"        for(const auto &v : yx) seg.emplace_back(v.size());",
		"    }",
		"",
		"    void set(CT x, CT y, S val){",
		"        int i = lower_bound(points.begin(), points.end(), Point{x, y}) - points.begin() + n;",
		"        while(i){",
		"            _set(i, Point{x, y}, val);",
		"            i = i >> 1;",
		"        }",
		"    }",
		"",
		"    S prod(CT xl, CT xr, CT yl, CT yr){",
		"        auto comp = [](const Point &lhs, const Point &rhs) {return lhs.first < rhs.first; };",
		"        int l = lower_bound(points.begin(), points.end(), Point{xl, yr}, comp) - points.begin() + n;",
		"        int r = lower_bound(points.begin(), points.end(), Point{xr, yr}, comp) - points.begin() + n;",
		"        S sml = e(), smr = e();",
		"        while(l < r){",
		"            if(l & 1) sml = op(sml, _prod(l++, yl, yr));",
		"            if(r & 1) smr = op(_prod(--r, yl, yr), smr);",
		"            l >>= 1;",
		"            r >>= 1;",
		"        }",
		"",
		"        return op(sml, smr);",
		"    }",
		"",
		"    S get(CT x, CT y){",
		"        return prod(x, x + 1, y, y + 1);",
		"    }",
		"};"
		],
		"description": "rangetree"
	},
	"compress": {
		"prefix": "atcoder_data_compress",
		"body": [
		"template<typename T>",
		"struct Compress{",
		"    vector<int> res;",
		"    map<T,int> org_2_comp;",
		"    map<int,T> comp_2_org;",
		"    Compress(vector<T> &vec, int base=0){init(vec,base);};",
		"    void init(vector<T> &vec, int base=0){",
		"        int N = vec.size();",
		"        res.assign(N,-1);",
		"        int cnt = base;",
		"        set<T> st;",
		"        for(int i=0;i<N;i++) {",
		"            st.insert(vec[i]);",
		"        }",
		"        for(auto itr=st.begin();itr!=st.end();itr++){",
		"            org_2_comp[*itr] = cnt;",
		"            comp_2_org[cnt] = *itr;",
		"            cnt++;",
		"        }",
		"        for(int i=0;i<N;i++) {",
		"            res[i] = org_2_comp[vec[i]];",
		"        }",
		"    }",
		"    // 座圧した値を返す",
		"    int get(int idx){",
		"        return res[idx];",
		"    }",
		"    // 座圧したリストを返す",
		"    vector<int> get_comp(){",
		"        return res;",
		"    }",
		"    // 元の値->座圧した値",
		"    int org2comp(T &val){",
		"        return org_2_comp[val];",
		"    }",
		"    // 座圧した値->元の値",
		"    T comp2org(int &idx){",
		"        return comp_2_org[idx];",
		"    }",
		"};",
		"",
		"template<typename T>",
		"struct Compress_multi{ // 同じ値を別に考える",
		"    vector<int> res;",
		"    map<T,int> org_2_min_comp, org_2_max_comp;",
		"    map<int,T> comp_2_org;",
		"    Compress_multi(vector<T> &vec, int base=0){init(vec,base);};",
		"    void init(vector<T> &vec, int base=0){",
		"        int N = vec.size();",
		"        res.assign(N,-1);",
		"        int cnt = base;",
		"        vector<pair<T,int>> val_and_idx(N);",
		"        rep(i,N) val_and_idx[i] = make_pair(vec[i], i);",
		"        sort(all(val_and_idx));",
		"        rep(i,N) {",
		"            T val = val_and_idx[i].first;",
		"            int idx = val_and_idx[i].second;",
		"            if (!org_2_min_comp.count(val)) org_2_min_comp[val] = cnt;",
		"            if (!org_2_max_comp.count(val)) org_2_max_comp[val] = cnt;",
		"            chmax(org_2_max_comp[val],cnt);",
		"            res[idx] = cnt;",
		"            comp_2_org[cnt] = val;",
		"            cnt++;",
		"        }",
		"    }",
		"    // 座圧した値を返す",
		"    int get(int idx){",
		"        return res[idx];",
		"    }",
		"    // 座圧したリストを返す",
		"    vector<int> get_comp(){",
		"        return res;",
		"    }",
		"    // 座圧した値->元の値",
		"    T comp2org(int &idx){",
		"        return comp_2_org[idx];",
		"    }",
		"    // 元の値->座圧した値で最小",
		"    int org2comp_min(T &val){",
		"        return org_2_min_comp[val];",
		"    }",
		"    // 元の値->座圧した値で最大",
		"    int org2comp_max(T &val){",
		"        return org_2_max_comp[val];",
		"    }",
		"};",
		""
		],
		"description": "compress"
	},
	"cumulate": {
		"prefix": "atcoder_data_cumulate2d",
		"body": [
		"struct cumulative_sum_2d{",
		"    int H,W;",
		"    vector<vector<ll>> val;",
		"    vector<vector<ll>> wa;",
		"    cumulative_sum_2d(int H_input, int W_input){init(H_input,W_input);}",
		"    void init(int H_input, int W_input){",
		"        H = H_input;",
		"        W = W_input;",
		"        val.assign(H,vector<ll>(W,0ll));",
		"        wa.assign(H+1,vector<ll>(W+1,0ll));",
		"    }",
		"    void set(int i, int j, ll value){",
		"        val[i][j] = value;",
		"    }",
		"    void add(int i, int j, ll value){",
		"        val[i][j] += value;",
		"    }",
		"    void build(){",
		"        for(int i=0;i<H;i++){",
		"            for(int j=0;j<W;j++){",
		"                wa[i+1][j+1] = wa[i][j+1] + wa[i+1][j] - wa[i][j] + val[i][j];",
		"            }",
		"        }",
		"    }",
		"    // [i1, i2) x [j1, j2)",
		"    ll query(int i1,int j1, int i2, int j2){",
		"        return wa[i2][j2] - wa[i2][j1] - wa[i1][j2] + wa[i1][j1];",
		"    }",
		"};",
		""
		],
		"description": "cumulate"
	},
	"2d_imos": {
		"prefix": "atcoder_data_imos2d",
		"body": [
		"struct imos_2d{",
		"    int H,W;",
		"    vector<vector<ll>> imos;",
		"    imos_2d(int H_input, int W_input){init(H_input, W_input);}",
		"    void init(int H_input, int W_input){",
		"        H = H_input;",
		"        W = W_input;",
		"        imos.assign(H+1,vector<ll>(W+1,0ll));",
		"    }",
		"    //[i1,i2)x[i2,j2)の長方形にvalを足す",
		"    void add(int i1, int j1, int i2, int j2, int val){",
		"        imos[i1][j1] += val;",
		"        imos[i2][j1] -= val;",
		"        imos[i1][j2] -= val;",
		"        imos[i2][j2] += val;",
		"    }",
		"    void build(){",
		"        for(int i=0;i<=H;i++){",
		"            for(int j=0;j<W;j++){",
		"                imos[i][j+1] += imos[i][j];",
		"            }",
		"        }",
		"        for(int j=0;j<=W;j++){",
		"            for(int i=0;i<H;i++){",
		"                imos[i+1][j] += imos[i][j];",
		"            }",
		"        }",
		"    }",
		"    ll query(int i, int j){",
		"        return imos[i][j];",
		"    }",
		"};",
		""
		],
		"description": "2d_imos"
	},
	"doubleheap": {
		"prefix": "atcoder_data_doubleheap",
		"body": [
		"struct DoubleHeap{",
		"    priority_queue<ll,vector<ll>,greater<ll>> min_hq;",
		"    priority_queue<ll,vector<ll>> max_hq;",
		"    map<ll,ll> mp; // {value, count}",
		"    ll _size = 0;",
		"    ll _total = 0;",
		"    DoubleHeap(){}",
		"    //",
		"    ll count(ll x){",
		"        return mp[x];",
		"    }",
		"    //",
		"    ll size(){",
		"        return _size;",
		"    }",
		"    //",
		"    ll sum(){",
		"        return _total;",
		"    }",
		"    //",
		"    void insert(ll x){",
		"        _size++;",
		"        _total += x;",
		"        min_hq.push(x);",
		"        max_hq.push(x);",
		"        mp[x]++;",
		"    }",
		"    // 削除した個数を返す",
		"    ll erase(ll x, ll n = LINF){",
		"        if (count(x) < n) n = count(x);",
		"        _size -= n;",
		"        _total -= n * x;",
		"        mp[x] -= n;",
		"        // if(mp[x]==0) mp.erase(x);",
		"        while((!min_hq.empty()) && (count(min_hq.top()) == 0)) min_hq.pop();",
		"        while((!max_hq.empty()) && (count(max_hq.top()) == 0)) max_hq.pop();",
		"        return n;",
		"    }",
		"    // ",
		"    void discard(ll x){",
		"        erase(x, 1);",
		"    }",
		"    // ",
		"    ll get_min(){",
		"        return min_hq.top();",
		"    };",
		"    //",
		"    ll get_max(){",
		"        return max_hq.top();",
		"    };",
		"    //",
		"    ll pop_min(){",
		"        ll v = get_min();",
		"        discard(v);",
		"        return v;",
		"    }",
		"    //",
		"    ll pop_max(){",
		"        ll v = get_max();",
		"        discard(v);",
		"        return v;",
		"    }",
		"    ",
		"    // debug",
		"    vector<pair<ll,ll>> dump(){",
		"        vector<pair<ll,ll>> res; // (value, cnt)",
		"        for(auto itr = mp.begin(); itr != mp.end(); itr++){",
		"            res.push_back(make_pair(itr->first, itr->second));",
		"        }",
		"        return res;",
		"    }",
		"};",
		""
		],
		"description": "doubleheap"
	},
	"swag": {
		"prefix": "atcoder_data_swag",
		"body": [
		"//https://qiita.com/Shirotsume/items/4a2837b5895ef9a7aeb1#foldable-stack-%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6",
		"template <class T, T (*op)(T,T), T (*e)()>",
		"struct SWAG {",
		"    vector<T> top, bottom, topfold, bottomfold;",
		"    SWAG(){",
		"        topfold.push_back(e());",
		"        bottomfold.push_back(e());",
		"    }",
		"    void _pushbottom(T x){",
		"        bottom.push_back(x);",
		"        bottomfold.push_back(op(bottomfold.back(), x));",
		"    }",
		"    T _popbottom(){",
		"        auto res = bottom.back();",
		"        bottom.pop_back();",
		"        bottomfold.pop_back();",
		"        return res;",
		"    }",
		"    void _pushtop(T x){",
		"        top.push_back(x);",
		"        topfold.push_back(op(x, topfold.back()));",
		"    }",
		"    T _poptop(){",
		"        auto res = top.back();",
		"        top.pop_back();",
		"        topfold.pop_back();",
		"        return res;",
		"    }",
		"    void push(T x){",
		"        _pushbottom(x);",
		"    }",
		"    void pushleft(T x){",
		"        _pushtop(x);",
		"    }",
		"    T fold(){",
		"        return op(topfold.back(), bottomfold.back());",
		"    }",
		"    T popleft(){",
		"        if (top.empty()){",
		"            vector<T> stack_;",
		"            while(!bottom.empty()){",
		"                auto x = _popbottom();",
		"                stack_.push_back(x);",
		"            }",
		"            int N = stack_.size();",
		"            reverse(all(stack_));",
		"            vector<T> stack1, stack2;",
		"            for(int i=0;i<N;i++){",
		"                if (i < (N+1)/2) stack1.push_back(stack_[i]);",
		"                else stack2.push_back(stack_[i]);",
		"            }",
		"            reverse(all(stack2));",
		"            for(int i=0;i<(N+1)/2;i++){",
		"                _pushtop(stack1.back());",
		"                stack1.pop_back();",
		"            }",
		"            for(int i=0;i<(N/2);i++){",
		"                _pushbottom(stack2.back());",
		"                stack2.pop_back();",
		"            }",
		"        }",
		"        if (top.empty()) return e();",
		"        else return _poptop();",
		"    }",
		"    T pop(){",
		"        if (bottom.empty()){",
		"            vector<T> stack_;",
		"            while(!top.empty()){",
		"                auto x = _poptop();",
		"                stack_.push_back(x);",
		"            }",
		"            int N = stack_.size();",
		"            vector<T> stack1, stack2;",
		"            for(int i=0;i<N;i++){",
		"                if (i < (N/2)) stack1.push_back(stack_[i]);",
		"                else stack2.push_back(stack_[i]);",
		"            }",
		"            reverse(all(stack2));",
		"            for(int i=0;i<(N+1)/2;i++){",
		"                _pushtop(stack2.back());",
		"                stack2.pop_back();",
		"            }",
		"            for(int i=0;i<(N/2);i++){",
		"                _pushtop(stack1.back());",
		"                stack1.pop_back();",
		"            }",
		"        }",
		"        if (bottom.empty()) return e();",
		"        else return _popbottom();",
		"    }",
		"};",
		"",
		"using S = ll;",
		"S op(S a, S b){return min(a, b);}",
		"S e(){return LINF;}",
		"// SWAG<S,op,e> sw;",
		""
		],
		"description": "swag"
	},
	"BinaryTrie": {
		"prefix": "atcoder_data_binary_trie",
		"body": [
		"// Binary Trie",
		"template<typename INT, size_t MAX_DIGIT> struct BinaryTrie {",
		"    struct Node {",
		"        size_t count;",
		"        Node *prev, *left, *right;",
		"        Node(Node *prev) : count(0), prev(prev), left(nullptr), right(nullptr) {}",
		"    };",
		"    INT lazy;",
		"    Node *root;",
		"",
		"    // constructor",
		"    BinaryTrie() : lazy(0), root(emplace(nullptr)) {}",
		"    inline size_t get_count(Node *v) const { return v ? v->count : 0; }",
		"",
		"    // add and get value of Node",
		"    inline void add(INT val) {",
		"        lazy ^= val;",
		"    }",
		"    inline INT get(Node *v) {",
		"        if (!v) return -1;",
		"        INT res = 0;",
		"        for (int i = 0; i < MAX_DIGIT; ++i) {",
		"            if (v == v->prev->right)",
		"                res |= INT(1)<<i;",
		"            v = v->prev;",
		"        }",
		"        return res ^ lazy;",
		"    }",
		"",
		"    // find Node* whose value is val",
		"    Node* find(INT val) {",
		"        INT nval = val ^ lazy;",
		"        Node *v = root;",
		"        for (int i = MAX_DIGIT-1; i >= 0; --i) {",
		"            bool flag = (nval >> i) & 1;",
		"            if (flag) v = v->right;",
		"            else v = v->left;",
		"            if (!v) return v;",
		"        }",
		"        return v;",
		"    }",
		"",
		"    // insert",
		"    inline Node* emplace(Node *prev) {",
		"        return new Node(prev);",
		"    }",
		"    void insert(INT val, size_t k = 1) {",
		"        INT nval = val ^ lazy;",
		"        Node *v = root;",
		"        for (int i = MAX_DIGIT-1; i >= 0; --i) {",
		"            bool flag = (nval >> i) & 1;",
		"            if (flag && !v->right) v->right = emplace(v);",
		"            if (!flag && !v->left) v->left = emplace(v);",
		"            if (flag) v = v->right;",
		"            else v = v->left;",
		"        }",
		"        v->count += k;",
		"        while ((v = v->prev)) v->count = get_count(v->left) + get_count(v->right);",
		"    }",
		"    ",
		"    // erase",
		"    Node* clear(Node *v) {",
		"        if (!v || get_count(v)) return v;",
		"        delete(v);",
		"        return nullptr;",
		"    }",
		"    bool erase(Node *v, size_t k = 1) {",
		"        if (!v) return false;",
		"        v->count -= k;",
		"        while ((v = v->prev)) {",
		"            v->left = clear(v->left);",
		"            v->right = clear(v->right);",
		"            v->count = get_count(v->left) + get_count(v->right);",
		"        }",
		"        return true;",
		"    }",
		"    bool erase(INT val) {",
		"        auto v = find(val);",
		"        return erase(v);",
		"    }",
		"    bool erase_k(INT val, size_t k = 1) {",
		"        return erase(find(val), k);",
		"    }",
		"",
		"    // max (with xor-addition of val) and min (with xor-addition of val)",
		"    Node* get_max(INT val = 0) {",
		"        INT nval = val ^ lazy;",
		"        Node* v = root;",
		"        for (int i = MAX_DIGIT-1; i >= 0; --i) {",
		"            bool flag = (nval >> i) & 1;",
		"            if (!v->right) v = v->left;",
		"            else if (!v->left) v = v->right;",
		"            else if (flag) v = v->left;",
		"            else v = v->right;",
		"        }",
		"        return v;",
		"    }",
		"    Node* get_min(INT val = 0) {",
		"        return get_max(~val & ((INT(1)<<MAX_DIGIT)-1));",
		"    }",
		"",
		"    // lower_bound, upper_bound",
		"    Node* get_cur_node(Node *v, int i) {",
		"        if (!v) return v;",
		"        Node *left = v->left, *right = v->right;",
		"        if ((lazy >> i) & 1) swap(left, right);",
		"        if (left) return get_cur_node(left, i+1);",
		"        else if (right) return get_cur_node(right, i+1);",
		"        return v;",
		"    }",
		"    Node* get_next_node(Node *v, int i) {",
		"        if (!v->prev) return nullptr;",
		"        Node *left = v->prev->left, *right = v->prev->right;",
		"        if ((lazy >> (i+1)) & 1) swap(left, right);",
		"        if (v == left && right) return get_cur_node(right, i);",
		"        else return get_next_node(v->prev, i+1);",
		"    }",
		"    Node* lower_bound(INT val) {",
		"        INT nval = val ^ lazy;",
		"        Node *v = root;",
		"        for (int i = MAX_DIGIT-1; i >= 0; --i) {",
		"            bool flag = (nval >> i) & 1;",
		"            if (flag && v->right) v = v->right;",
		"            else if (!flag && v->left) v = v->left;",
		"            else if ((val >> i) & 1) return get_next_node(v, i);",
		"            else return get_cur_node(v, i);",
		"        }",
		"        return v;",
		"    }",
		"    Node* upper_bound(INT val) {",
		"        return lower_bound(val + 1);",
		"    }",
		"    size_t order_of_val(INT val) {",
		"        Node *v = root;",
		"        size_t res = 0;",
		"        for (int i = MAX_DIGIT-1; i >= 0; --i) {",
		"            Node *left = v->left, *right = v->right;",
		"            if ((lazy >> i) & 1) swap(left, right);",
		"            bool flag = (val >> i) & 1;",
		"            if (flag) {",
		"                res += get_count(left);",
		"                v = right;",
		"            }",
		"            else v = left;",
		"        }",
		"        return res;",
		"    }",
		"",
		"    // k-th, k is 0-indexed",
		"    Node* get_kth(size_t k, INT val = 0) {",
		"        Node *v = root;",
		"        if (get_count(v) <= k) return nullptr;",
		"        for (int i = MAX_DIGIT-1; i >= 0; --i) {",
		"            bool flag = (lazy >> i) & 1;",
		"            Node *left = (flag ? v->right : v->left);",
		"            Node *right = (flag ? v->left : v->right);",
		"            if (get_count(left) <= k) k -= get_count(left), v = right;",
		"            else v = left;",
		"        }",
		"        return v;",
		"    }",
		"",
		"        // debug",
		"    void print(Node *v, string prefix = \"\") {",
		"        if (!v) return;",
		"        cout << prefix << \": \" << v->count << endl;",
		"        print(v->left, prefix + \"0\");",
		"        print(v->right, prefix + \"1\");",
		"    }",
		"    void print() {",
		"        print(root);",
		"    }",
		"    vector<INT> eval(Node *v, int digit) const {",
		"        vector<INT> res;",
		"        if (!v) return res;",
		"        if (!v->left && !v->right) {",
		"            for (int i = 0; i < get_count(v); ++i) res.push_back(0);",
		"            return res;",
		"        }",
		"        const auto& left = eval(v->left, digit-1);",
		"        const auto& right = eval(v->right, digit-1);",
		"        for (auto val : left) res.push_back(val);",
		"        for (auto val : right) res.push_back(val + (INT(1)<<digit));",
		"        return res;",
		"    }",
		"    vector<INT> eval() const {",
		"        auto res = eval(root, MAX_DIGIT-1);",
		"        for (auto &val : res) val ^= lazy;",
		"        return res;",
		"    }",
		"    friend ostream& operator << (ostream &os, const BinaryTrie<INT, MAX_DIGIT> &bt) {",
		"        auto res = bt.eval();",
		"        for (auto val : res) os << val << \" \";",
		"        return os;",
		"    }",
		"};",
		"//https://drken1215.hatenablog.com/entry/2020/02/29/035900",
		"//BinaryTrie<int,30> trie;",
		"//trie.root->count -> 集合のサイズ",
		"//trie.get_count(x) -> xの個数",
		"//trie.xor_query(val) -> 全体にvalをxor",
		"//trie.get(v) -> 遅延伝搬のため,取り出す時は基本的にこれを使う",
		"//trie.find(x) -> xがあるか",
		"//trie.insert(x,k=1) -> xをk個挿入",
		"//trie.erase(x) -> xを1個削除",
		"//trie.erase_k(x,k=1) -> xをk個削除",
		"//trie.get_max(val = 0) -> valとxorを取った時の最大値",
		"//trie.get_min(val = 0) -> valとxorを取った時の最小値",
		"//trie.get_kth(x) -> x番目(0-indexed)の値を取り出す.",
		"//trie.lower_bound(x) -> ",
		"//trie.upper_bound(x) -> ",
		"//trie.order_of_val(x) -> xが何番目か(0-indexed),xが集合にある場合のみ有効",
		"//trie.get_kth(x) -> 0indexedでx番目の値、x個無いならnullptr(<-int型、!get_kth(val)は可能)",
		"",
		],
		"description": "BinaryTrie"
	},
	"Segtree_2d": {
		"prefix": "atcoder_data_Segtree2d",
		"body": [
		"template <typename T, typename F>",
		"struct SegmentTree2D {",
		"    private:",
		"        int id(int h, int w) { return h * 2 * W + w; }",
		"    public:",
		"        int H, W;",
		"        vector<T> seg;",
		"        const F f;",
		"        const T I;",
		"    SegmentTree2D(int h, int w, F _f, const T& i) : f(_f), I(i) { init(h, w); }",
		"",
		"    void init(int h, int w) {",
		"        H = W = 1;",
		"        while (H < h) H <<= 1;",
		"        while (W < w) W <<= 1;",
		"        seg.assign(4 * H * W, I);",
		"    }",
		"",
		"    // build にのみ呼ぶ",
		"    void set(int h, int w, const T& x) { seg[id(h + H, w + W)] = x; }",
		"",
		"    void build() {",
		"    // w in [W, 2W)",
		"        for (int w = W; w < 2 * W; w++) {",
		"            for (int h = H - 1; h; h--) {",
		"                seg[id(h, w)] = f(seg[id(2 * h + 0, w)], seg[id(2 * h + 1, w)]);",
		"            }",
		"        }",
		"    // h in [0, 2H)",
		"        for (int h = 0; h < 2 * H; h++) {",
		"            for (int w = W - 1; w; w--) {",
		"                seg[id(h, w)] = f(seg[id(h, 2 * w + 0)], seg[id(h, 2 * w + 1)]);",
		"            }",
		"        }",
		"    }",
		"",
		"    T get(int h, int w)  { return seg[id(h + H, w + W)]; }",
		"    // T operator()(int h, int w) const { return seg[id(h + H, w + W)]; }",
		"",
		"    void update(int h, int w, const T& x) {",
		"        h += H, w += W;",
		"        seg[id(h, w)] = x;",
		"        for (int i = h >> 1; i; i >>= 1) {",
		"            seg[id(i, w)] = f(seg[id(2 * i + 0, w)], seg[id(2 * i + 1, w)]);",
		"        }",
		"        for (; h; h >>= 1) {",
		"            for (int j = w >> 1; j; j >>= 1) {",
		"                seg[id(h, j)] = f(seg[id(h, 2 * j + 0)], seg[id(h, 2 * j + 1)]);",
		"            }",
		"        }",
		"    }",
		"",
		"    T _inner_query(int h, int w1, int w2) {",
		"        T res = I;",
		"        for (; w1 < w2; w1 >>= 1, w2 >>= 1) {",
		"            if (w1 & 1) res = f(res, seg[id(h, w1)]), w1++;",
		"            if (w2 & 1) --w2, res = f(res, seg[id(h, w2)]);",
		"        }",
		"        return res;",
		"    }",
		"",
		"  // [ (h1,w1), (h2,w2) ) 半開",
		"    T prod(int h1, int w1, int h2, int w2) {",
		"        if (h1 >= h2 || w1 >= w2) return I;",
		"        T res = I;",
		"        h1 += H, h2 += H, w1 += W, w2 += W;",
		"        for (; h1 < h2; h1 >>= 1, h2 >>= 1) {",
		"            if (h1 & 1) res = f(res, _inner_query(h1, w1, w2)), h1++;",
		"            if (h2 & 1) --h2, res = f(res, _inner_query(h2, w1, w2));",
		"        }",
		"        return res;",
		"    }",
		"};",
		"",
		"/**",
		" * @brief 二次元セグメント木",
		" * @docs docs/data-structure-2d/2d-segment-tree.md",
		" * https://nyaannyaan.github.io/library/data-structure-2d/2d-segment-tree.hpp",
		" */",
		"// ",
		"// ll f(ll a, ll b){return a + b;}",
		"// ll e(){return 0ll;}",
		"// SegmentTree2D seg(H,W,f,e());",
		""
		],
		"description": "Segtree_2d"
	},
	"bit2d": {
		"prefix": "atcoder_data_bit2d",
		"body": [
		"template<typename T>",
		"struct BIT2D{",
		"    int H, W;",
		"    vector<vector<T>> bit;",
		"    BIT2D(int _H, int _W) : H(_H), W(_W){",
		"        bit.resize(H, vector<T>(W, 0));",
		"    }",
		"    // data[i][j] += v;",
		"    void add(int i, int j, T v){",
		"        for(int a = i + 1; a <= H; a += (a & -a)){",
		"            for(int b = j + 1; b <= W; b += (b & - b)){",
		"                bit[a - 1][b - 1] += v;",
		"            }",
		"        }",
		"    }",
		"    // [0, i) x [0, j)",
		"    T _sum(int i, int j){",
		"        T s = 0;",
		"        for(int a = i; a > 0; a -= (a & -a)){",
		"            for(int b = j; b > 0; b -= (b & -b)){",
		"                s += bit[a - 1][b - 1];",
		"            }",
		"        }",
		"        return s;",
		"    }",
		"    // [i1, i2) x [j1, j2)",
		"    T sum(int i1, int j1, int i2, int j2){",
		"        return _sum(i2, j2) - _sum(i2, j1) - _sum(i1, j2) + _sum(i1, j1);",
		"    }",
		"};",
		""
		],
		"description": "bit2d"
	},
	"Wavelet_Matrix": {
		"prefix": "atcoder_data_wavelet_matrix",
		"body": [
		"// https://github.com/MitI-7/WaveletMatrix",
		"enum {",
		"    NOTFOUND = 0xFFFFFFFFFFFFFFFFLLU // 18446744073709551615 ~ 1.8x10^20",
		"};",
		"",
		"class SuccinctBitVector {",
		"private:",
		"    const uint64_t size;    // ビットベクトルのサイズ",
		"    static const uint64_t blockBitNum = 16;",
		"    static const uint64_t LEVEL_L = 512;",
		"    static const uint64_t LEVEL_S = 16;",
		"",
		"    std::vector<uint64_t> L;   // 大ブロック",
		"    std::vector<uint16_t> S;   // 小ブロック",
		"    std::vector<uint16_t> B;   // ビットベクトル",
		"",
		"    uint64_t numOne = 0;       // 1bitの数",
		"",
		"public:",
		"    explicit SuccinctBitVector(const uint64_t n) : size(n) {",
		"        const uint64_t s = (n + blockBitNum - 1) / blockBitNum + 1;   // ceil(n, blockSize)",
		"        this->B.assign(s, 0);",
		"        this->L.assign(n / LEVEL_L + 1, 0);",
		"        this->S.assign(n / LEVEL_S + 1, 0);",
		"    }",
		"",
		"    // B[pos] = bit",
		"    void setBit(const uint64_t bit, const uint64_t pos){",
		"        assert(bit == 0 or bit == 1);",
		"        assert(pos < this->size);",
		"",
		"        const uint64_t blockPos = pos / blockBitNum;",
		"        const uint64_t offset = pos % blockBitNum;",
		"        if (bit == 1) { B.at(blockPos) |= (1LLU << offset); }",
		"        else          { B.at(blockPos) &= (~(1LLU << offset)); }",
		"    }",
		"",
		"    // B[pos]",
		"    uint64_t access(const uint64_t pos) {",
		"        assert(pos < this->size);",
		"        const uint64_t blockPos = pos / blockBitNum;",
		"        const uint64_t offset   = pos % blockBitNum;",
		"        return ((B.at(blockPos) >> offset) & 1);",
		"    }",
		"",
		"    void build() {",
		"        uint64_t num = 0;",
		"        for (uint64_t i = 0; i <= size; i++){",
		"            if (i % LEVEL_L == 0) {",
		"                L.at(i / LEVEL_L) = num;",
		"            }",
		"            if (i % LEVEL_S == 0) {",
		"                S.at(i / LEVEL_S) = num - L.at(i / LEVEL_L);",
		"            }",
		"            if (i != size and i % blockBitNum == 0) {",
		"                num += this->popCount(this->B.at(i / blockBitNum));",
		"            }",
		"        }",
		"        this-> numOne = num;",
		"    }",
		"",
		"    // B[0, pos)のbitの数",
		"    uint64_t rank(const uint64_t bit, const uint64_t pos) {",
		"        assert(bit == 0 or bit == 1);",
		"        assert(pos <= this->size);",
		"",
		"        if (bit) {",
		"            return L[pos / LEVEL_L] + S[pos / LEVEL_S] + popCount(B[pos / blockBitNum] & ((1 << (pos % blockBitNum)) - 1));",
		"        }",
		"        else {",
		"            return pos - rank(1, pos);",
		"        }",
		"    }",
		"",
		"    // rank番目のbitの位置 + 1(rankは1-origin)",
		"    uint64_t select(const uint64_t bit, const uint64_t rank) {",
		"        assert(bit == 0 or bit == 1);",
		"        assert(rank > 0);",
		"        if (bit == 0 and rank > this->size - this-> numOne) { return NOTFOUND; }",
		"        if (bit == 1 and rank > this-> numOne)              { return NOTFOUND; }",
		"",
		"        // 大ブロックL内を検索",
		"        uint64_t large_idx = 0;",
		"        {",
		"            uint64_t left = 0;",
		"            uint64_t right = L.size();",
		"            while (right - left > 1) {",
		"                uint64_t mid = (left + right) / 2;",
		"                uint64_t r = L.at(mid);",
		"                r = (bit) ? r : mid * LEVEL_L - L.at(mid);",
		"",
		"                if (r < rank) {",
		"                    left = mid;",
		"                    large_idx = mid;",
		"                } else {",
		"                    right = mid;",
		"                }",
		"            }",
		"        }",
		"",
		"        // 小ブロックS内を検索",
		"        uint64_t small_idx = (large_idx * LEVEL_L) / LEVEL_S;",
		"        {",
		"            uint64_t left = (large_idx * LEVEL_L) / LEVEL_S;",
		"            uint64_t right = std::min(((large_idx  + 1) * LEVEL_L) / LEVEL_S, (uint64_t)S.size());",
		"            while (right - left > 1) {",
		"                uint64_t mid = (left + right) / 2;",
		"                uint64_t r = L.at(large_idx) + S.at(mid);",
		"                r = (bit) ? r :mid * LEVEL_S - r;",
		"",
		"                if (r < rank) {",
		"                    left = mid;",
		"                    small_idx = mid;",
		"                } else {",
		"                    right = mid;",
		"                }",
		"            }",
		"        }",
		"",
		"        // Bをブロック単位で順番に探索",
		"        uint64_t rank_pos = 0;",
		"        {",
		"            const uint64_t begin_block_idx = (small_idx * LEVEL_S) / blockBitNum;",
		"            uint64_t total_bit = L.at(large_idx) + S.at(small_idx);",
		"            if (bit == 0) {",
		"                total_bit = small_idx * LEVEL_S - total_bit;",
		"            }",
		"            for (uint64_t i = 0;; ++i) {",
		"                uint64_t b = popCount(B.at(begin_block_idx + i));",
		"                if (bit == 0) {",
		"                    b = blockBitNum - b;",
		"                }",
		"                if (total_bit + b >= rank) {",
		"                    uint64_t block = (bit) ? B.at(begin_block_idx + i) : ~B.at(begin_block_idx + i);",
		"                    rank_pos = (begin_block_idx + i) * blockBitNum + selectInBlock(block, rank - total_bit);",
		"                    break;",
		"                }",
		"                total_bit += b;",
		"            }",
		"        }",
		"",
		"        return rank_pos + 1;",
		"    }",
		"",
		"    uint64_t getNumOne() const {",
		"        return numOne;",
		"    }",
		"",
		"    void debug() {",
		"        std::cout << \"LEVEL_L(\" << L.size() << \")\" << std::endl;",
		"        for (uint64_t i = 0 ; i < L.size(); ++i) {",
		"            std::cout << L.at(i) << \", \";",
		"        }",
		"        std::cout << std::endl;",
		"        std::cout << \"LEVEL_S(\" << S.size() << \")\" << std::endl;",
		"        for (uint64_t i = 0 ; i < S.size(); ++i) {",
		"            std::cout << S.at(i) << \", \";",
		"        }",
		"        std::cout << std::endl;",
		"    }",
		"",
		"private:",
		"    uint64_t popCount(uint64_t x) {",
		"        x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL);",
		"        x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);",
		"        x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;",
		"        x = x + (x >>  8);",
		"        x = x + (x >> 16);",
		"        x = x + (x >> 32);",
		"        return x & 0x7FLLU;",
		"    }",
		"",
		"    uint64_t selectInBlock(uint64_t x, uint64_t rank) {",
		"        uint64_t x1 = x - ((x & 0xAAAAAAAAAAAAAAAALLU) >> 1);",
		"        uint64_t x2 = (x1 & 0x3333333333333333LLU) + ((x1 >> 2) & 0x3333333333333333LLU);",
		"        uint64_t x3 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FLLU;",
		"",
		"        uint64_t pos = 0;",
		"        for (;;  pos += 8){",
		"            uint64_t rank_next = (x3 >> pos) & 0xFFLLU;",
		"            if (rank <= rank_next) break;",
		"            rank -= rank_next;",
		"        }",
		"",
		"        uint64_t v2 = (x2 >> pos) & 0xFLLU;",
		"        if (rank > v2) {",
		"            rank -= v2;",
		"            pos += 4;",
		"        }",
		"",
		"        uint64_t v1 = (x1 >> pos) & 0x3LLU;",
		"        if (rank > v1){",
		"            rank -= v1;",
		"            pos += 2;",
		"        }",
		"",
		"        uint64_t v0  = (x >> pos) & 0x1LLU;",
		"        if (v0 < rank){",
		"            rank -= v0;",
		"            pos += 1;",
		"        }",
		"",
		"        return pos;",
		"    }",
		"};",
		"",
		"class WaveletMatrix {",
		"private:",
		"    std::vector<SuccinctBitVector> bit_arrays;",
		"    std::vector<uint64_t> begin_one;                    // 各bitに着目したときの1の開始位置",
		"    std::map<uint64_t, uint64_t> begin_alphabet;        // 最後のソートされた配列で各文字の開始位置",
		"    std::vector<std::vector<uint64_t>> cumulative_sum;  // 各bitに着目したときの累積和",
		"",
		"    uint64_t size;                                 // 与えられた配列のサイズ",
		"    uint64_t maximum_element;                      // 文字数",
		"    uint64_t bit_size;                             // 文字を表すのに必要なbit数",
		"",
		"public:",
		"    WaveletMatrix (const std::vector<uint64_t> &array) {",
		"        assert(array.size() > 0);",
		"        size = array.size();",
		"        maximum_element =  *max_element(array.begin(), array.end()) + 1;",
		"        bit_size = get_num_of_bit(maximum_element);",
		"        if (bit_size == 0) {",
		"            bit_size = 1;",
		"        }",
		"",
		"        for (uint64_t i = 0; i < bit_size; ++i) {",
		"            SuccinctBitVector sv(size);",
		"            bit_arrays.push_back(sv);",
		"        }",
		"        this->begin_one.resize(bit_size);",
		"        this->cumulative_sum.resize(bit_size + 1, std::vector<uint64_t>(size + 1, 0));",
		"",
		"        for (uint64_t j = 0; j < array.size(); ++j) {",
		"            this->cumulative_sum.at(0).at(j + 1) = this->cumulative_sum.at(0).at(j) + array[j];",
		"        }",
		"",
		"        std::vector<uint64_t> v(array);",
		"        for (uint64_t i = 0; i < bit_size; ++i) {",
		"",
		"            std::vector<uint64_t> temp;",
		"            // 0をtempにいれてく",
		"            for (uint64_t j = 0; j < v.size(); ++j) {",
		"                uint64_t c = v.at(j);",
		"                uint64_t bit = (c >> (bit_size - i - 1)) & 1;  // 上からi番目のbit",
		"                if (bit == 0) {",
		"                    temp.push_back(c);",
		"                    bit_arrays.at(i).setBit(0, j);",
		"                }",
		"            }",
		"",
		"            this->begin_one.at(i) = temp.size();",
		"",
		"            // 1をtempにいれてく",
		"            for (uint64_t j = 0; j < v.size(); ++j) {",
		"                uint64_t c = v.at(j);",
		"                uint64_t bit = (c >> (bit_size - i - 1)) & 1;  // 上からi番目のbit",
		"                if (bit == 1) {",
		"                    temp.push_back(c);",
		"                    bit_arrays.at(i).setBit(1, j);",
		"                }",
		"            }",
		"",
		"            for (uint64_t j = 0; j < temp.size(); ++j) {",
		"                this->cumulative_sum.at(i + 1).at(j + 1) = this->cumulative_sum.at(i + 1).at(j) + temp.at(j);",
		"            }",
		"",
		"            bit_arrays.at(i).build();",
		"            v = temp;",
		"        }",
		"",
		"        // ソートされた配列内での各文字の位置を取得",
		"        for (int i = v.size() - 1; i >= 0; --i) {",
		"            this->begin_alphabet[v.at(i)] = i;",
		"        }",
		"    }",
		"",
		"    // v[pos]",
		"    uint64_t access(uint64_t pos) {",
		"        if (pos >= this->size) { return NOTFOUND; }",
		"",
		"        uint64_t c = 0;",
		"        for (uint64_t i = 0; i < bit_arrays.size(); ++i) {",
		"            uint64_t bit = bit_arrays.at(i).access(pos);   // もとの数値のi番目のbit",
		"            c = (c <<= 1) | bit;",
		"            pos = bit_arrays.at(i).rank(bit, pos);",
		"            if (bit) {",
		"                pos += this->begin_one.at(i);",
		"            }",
		"        }",
		"        return c;",
		"    }",
		"",
		"    // i番目のcの位置 + 1を返す。rankは1-origin",
		"    uint64_t select(uint64_t c, uint64_t rank) {",
		"        assert(rank > 0);",
		"        if (c >= maximum_element) {",
		"            return NOTFOUND;",
		"        }",
		"        if (this->begin_alphabet.find(c) == this->begin_alphabet.end()) {",
		"            return NOTFOUND;",
		"        }",
		"",
		"        uint64_t index = this->begin_alphabet.at(c) + rank;",
		"        for (uint64_t i = 0; i < bit_arrays.size(); ++i){",
		"            uint64_t bit = ((c >> i) & 1);      // 下からi番目のbit",
		"            if (bit == 1) {",
		"                index -= this->begin_one.at(bit_size - i - 1);",
		"            }",
		"            index = this->bit_arrays.at(bit_size - i - 1).select(bit, index);",
		"        }",
		"        return index;",
		"    }",
		"",
		"    // v[begin_pos, end_pos)で最大値のindexを返す",
		"    uint64_t maxRange(uint64_t begin_pos, uint64_t end_pos) {",
		"        return quantileRange(begin_pos, end_pos, end_pos - begin_pos - 1);",
		"    }",
		"",
		"    // v[begin_pos, end_pos)で最小値のindexを返す",
		"    uint64_t minRange(uint64_t begin_pos, uint64_t end_pos) {",
		"        return quantileRange(begin_pos, end_pos, 0);",
		"    }",
		"",
		"    // v[begin_pos, end_pos)でk番目に小さい数値のindexを返す(kは0-origin)",
		"    // つまり小さい順に並べてk番目の値",
		"    uint64_t quantileRange(uint64_t begin_pos, uint64_t end_pos, uint64_t k) {",
		"        if ((end_pos > size || begin_pos >= end_pos) || (k >= end_pos - begin_pos)) {",
		"            return NOTFOUND;",
		"        }",
		"",
		"        uint64_t val = 0;",
		"        for (uint64_t i = 0; i < bit_size; ++i) {",
		"            const uint64_t num_of_zero_begin = bit_arrays.at(i).rank(0, begin_pos);",
		"            const uint64_t num_of_zero_end = bit_arrays.at(i).rank(0, end_pos);",
		"            const uint64_t num_of_zero = num_of_zero_end - num_of_zero_begin;     // beginからendまでにある0の数",
		"            const uint64_t bit = (k < num_of_zero) ? 0 : 1;                       // k番目の値の上からi番目のbitが0か1か",
		"",
		"            if (bit) {",
		"                k -= num_of_zero;",
		"                begin_pos = this->begin_one.at(i) + begin_pos - num_of_zero_begin;",
		"                end_pos = this->begin_one.at(i) + end_pos - num_of_zero_end;",
		"            }",
		"            else {",
		"                begin_pos = num_of_zero_begin;",
		"                end_pos = num_of_zero_begin + num_of_zero;",
		"            }",
		"",
		"            val = ((val << 1) | bit);",
		"        }",
		"",
		"        uint64_t left = 0;",
		"        for (uint64_t i = 0; i < bit_size; ++i) {",
		"            const uint64_t bit = (val >> (bit_size - i - 1)) & 1;  // 上からi番目のbit",
		"            left = bit_arrays.at(i).rank(bit, left);               // cのi番目のbitと同じ数値の数",
		"            if (bit) {",
		"                left += this->begin_one.at(i);",
		"            }",
		"        }",
		"",
		"        const uint64_t rank = begin_pos + k - left + 1;",
		"        return select(val, rank) - 1;",
		"    }",
		"",
		"    // v[0, pos)のcの数",
		"    uint64_t rank(uint64_t c, uint64_t pos) {",
		"        assert(pos < size);",
		"        if (c >= maximum_element) {",
		"            return 0;",
		"        }",
		"        if (this->begin_alphabet.find(c) == this->begin_alphabet.end()) {",
		"            return 0;",
		"        }",
		"",
		"        for (uint64_t i = 0; i < bit_size; ++i) {",
		"            uint64_t bit = (c >> (bit_size - i - 1)) & 1;  // 上からi番目のbit",
		"            pos = bit_arrays.at(i).rank(bit, pos);         // cのi番目のbitと同じ数値の数",
		"            if (bit) {",
		"                pos += this->begin_one.at(i);",
		"            }",
		"        }",
		"",
		"        uint64_t begin_pos = this->begin_alphabet.at(c);",
		"        return pos - begin_pos;",
		"    }",
		"",
		"    // v[begin_pos, end_pos)で[min, max)に入る値の個数",
		"    uint64_t rangeFreq(uint64_t begin_pos, uint64_t end_pos, uint64_t min_c, uint64_t max_c) {",
		"        if ((end_pos > size || begin_pos >= end_pos) || (min_c >= max_c) || min_c >= maximum_element) {",
		"            return 0;",
		"        }",
		"",
		"        const auto maxi_t = rankAll(max_c, begin_pos, end_pos);",
		"        const auto mini_t = rankAll(min_c, begin_pos, end_pos);",
		"        return std::get<1>(maxi_t) - std::get<1>(mini_t);",
		"    }",
		"",
		"    // v[0, pos)でcより小さい文字の数 <- 恐らくv[begin, end)",
		"    uint64_t rankLessThan(uint64_t c, uint64_t begin, uint64_t end) {",
		"        auto t = rankAll(c, begin, end);",
		"        return std::get<1>(t);",
		"    }",
		"",
		"    // v[0, pos)でcより大きい文字の数 <- 恐らくv[begin, end)",
		"    uint64_t rankMoreThan(uint64_t c, uint64_t begin, uint64_t end) {",
		"        auto t = rankAll(c, begin, end);",
		"        return std::get<2>(t);",
		"    }",
		"",
		"    // v[begin, end)で(cと同じ値の数、cより小さい値の数、cより大きい値の数)を求める",
		"    std::tuple<uint64_t, uint64_t, uint64_t> rankAll(const uint64_t c, uint64_t begin, uint64_t end) {",
		"        assert(end <= size);",
		"        const uint64_t num = end - begin;",
		"",
		"        if (begin >= end) {",
		"            return std::make_tuple(0, 0, 0);",
		"        }",
		"        if (c >= maximum_element || end == 0) {",
		"            return std::make_tuple(0, num, 0);",
		"        }",
		"",
		"        uint64_t rank_less_than = 0, rank_more_than = 0;",
		"        for (size_t i = 0; i < bit_size && begin < end; ++i) {",
		"            const uint64_t bit = (c >> (bit_size - i - 1)) & 1;",
		"",
		"            const uint64_t rank0_begin = this->bit_arrays.at(i).rank(0, begin);",
		"            const uint64_t rank0_end = this->bit_arrays.at(i).rank(0, end);",
		"            const uint64_t rank1_begin = begin - rank0_begin;",
		"            const uint64_t rank1_end = end - rank0_end;",
		"",
		"            if (bit) {",
		"                rank_less_than += (rank0_end - rank0_begin);    // i番目のbitが0のものは除外される",
		"                begin = this->begin_one.at(i) + rank1_begin;",
		"                end = this->begin_one.at(i) + rank1_end;",
		"            } else {",
		"                rank_more_than += (rank1_end - rank1_begin);    // i番目のbitが1のものは除外される",
		"                begin = rank0_begin;",
		"                end = rank0_end;",
		"            }",
		"        }",
		"",
		"        const uint64_t rank = num - rank_less_than - rank_more_than;",
		"        return std::make_tuple(rank, rank_less_than, rank_more_than);",
		"    }",
		"",
		"    // T[s, e)で出現回数が多い順にk個の(値,頻度)を返す",
		"    // 頻度が同じ場合は値が小さいものが優先される",
		"    std::vector<std::pair<uint64_t, uint64_t>> topk(uint64_t s, uint64_t e, uint64_t k) {",
		"        assert(s < e);",
		"        std::vector<std::pair<uint64_t, uint64_t>> result;",
		"",
		"        // (頻度,深さ,値)の順でソート",
		"        auto c = [](const std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t> &l, const std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t> &r) {",
		"            // width",
		"            if (std::get<0>(l) != std::get<0>(r)) {",
		"                return std::get<0>(l) < std::get<0>(r);",
		"            }",
		"            // depth",
		"            if (std::get<3>(l) != std::get<3>(r)) {",
		"                return std::get<3>(l) > std::get<3>(r);",
		"            }",
		"            // value",
		"            if (std::get<4>(l) != std::get<4>(r)) {",
		"                return std::get<4>(l) > std::get<4>(r);",
		"            }",
		"            return true;",
		"        };",
		"",
		"        std::priority_queue<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>, std::vector<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>>, decltype(c)> que(c);  // width, left, right, depth, value",
		"        que.push(std::make_tuple(e - s, s, e, 0, 0));",
		"",
		"        while (not que.empty()) {",
		"            auto element = que.top(); que.pop();",
		"            uint64_t width, left, right, depth, value;",
		"            std::tie(width, left, right, depth, value) = element;",
		"",
		"            if (depth >= this->bit_size) {",
		"                result.emplace_back(std::make_pair(value, right - left));",
		"                if (result.size() >= k) {",
		"                    break;",
		"                }",
		"                continue;",
		"            }",
		"",
		"            // 0",
		"            const uint64_t left0 = this->bit_arrays.at(depth).rank(0, left);",
		"            const uint64_t right0 = this->bit_arrays.at(depth).rank(0, right);",
		"            if (left0 < right0) {",
		"                que.push(std::make_tuple(right0 - left0, left0, right0, depth + 1, value));",
		"            }",
		"",
		"            // 1",
		"            const uint64_t left1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, left);",
		"            const uint64_t right1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, right);",
		"            if (left1 < right1) {",
		"                que.push(std::make_tuple(right1 - left1, left1, right1, depth + 1, value | (1 << (bit_size - depth - 1))));",
		"            }",
		"        }",
		"",
		"        return result;",
		"    };",
		"",
		"    // T[begin_pos, end_pos)でx <= c < yを満たすcの和を返す",
		"    uint64_t rangeSum(const uint64_t begin, const uint64_t end, const uint64_t x, const uint64_t y) {",
		"        return rangeSum(begin, end, 0, 0, x, y);",
		"    }",
		"",
		"    // T[begin_pos, end_pos)でx <= c < yを満たす最大のcを返す",
		"    uint64_t prevValue(const uint64_t begin_pos, const uint64_t end_pos, const uint64_t x, uint64_t y) {",
		"        assert(end_pos <= size);",
		"        const uint64_t num = end_pos - begin_pos;",
		"",
		"        if (x >= y or y == 0) {",
		"            return NOTFOUND;",
		"        }",
		"        if (y > maximum_element) {",
		"            y = maximum_element;",
		"        }",
		"",
		"        if (begin_pos >= end_pos) {",
		"            return NOTFOUND;",
		"        }",
		"        if (x >= maximum_element || end_pos == 0) {",
		"            return NOTFOUND;",
		"        }",
		"",
		"        y--; // x <= c <= yにする",
		"",
		"        std::stack<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, bool>> s;   // (begin, end, depth, c, tight)",
		"        s.emplace(std::make_tuple(begin_pos, end_pos, 0, 0, true));",
		"",
		"        while (not s.empty()) {",
		"            uint64_t b, e, depth, c;",
		"            bool tight;",
		"            std::tie(b, e, depth, c, tight) = s.top(); s.pop();",
		"",
		"            if (depth == bit_size) {",
		"                if (c >= x) {",
		"                    return c;",
		"                }",
		"                continue;",
		"            }",
		"",
		"            const uint64_t bit = (y >> (bit_size - depth - 1)) & 1;",
		"",
		"            const uint64_t rank0_begin = this->bit_arrays.at(depth).rank(0, b);",
		"            const uint64_t rank0_end = this->bit_arrays.at(depth).rank(0, e);",
		"            const uint64_t rank1_begin = b - rank0_begin;",
		"            const uint64_t rank1_end = e - rank0_end;",
		"",
		"            // d番目のbitが0のものを使う",
		"            const uint64_t b0 = rank0_begin;",
		"            const uint64_t e0 = rank0_end;",
		"            if (b0 != e0) { // 範囲がつぶれてない",
		"                const uint64_t c0 = ((c << 1) | 0);",
		"                s.emplace(std::make_tuple(b0, e0, depth + 1, c0, tight and bit == 0));",
		"            }",
		"",
		"            // d番目のbitが1のものを使う",
		"            const uint64_t b1 = this->begin_one.at(depth) + rank1_begin;",
		"            const uint64_t e1 = this->begin_one.at(depth) + rank1_end;",
		"            if (b1 != e1) {",
		"                if (not tight or bit == 1) {",
		"                    const auto c1 = ((c << 1) | 1);",
		"                    s.emplace(std::make_tuple(b1, e1, depth + 1, c1, tight));",
		"                }",
		"            }",
		"        }",
		"",
		"        return NOTFOUND;",
		"    }",
		"",
		"    // T[begin_pos, end_pos)でx <= c < yを満たす最小のcを返す",
		"    uint64_t nextValue(const uint64_t begin_pos, const uint64_t end_pos, const uint64_t x, const uint64_t y) {",
		"        assert(end_pos <= size);",
		"        const uint64_t num = end_pos - begin_pos;",
		"",
		"        if (x >= y or y == 0) {",
		"            return NOTFOUND;",
		"        }",
		"",
		"        if (begin_pos >= end_pos) {",
		"            return NOTFOUND;",
		"        }",
		"        if (x >= maximum_element || end_pos == 0) {",
		"            return NOTFOUND;",
		"        }",
		"",
		"        std::stack<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, bool>> s;   // (begin, end, depth, c, tight)",
		"        s.emplace(std::make_tuple(begin_pos, end_pos, 0, 0, true));",
		"",
		"        while (not s.empty()) {",
		"            uint64_t b, e, depth, c;",
		"            bool tight;",
		"            std::tie(b, e, depth, c, tight) = s.top(); s.pop();",
		"",
		"            if (depth == bit_size) {",
		"                if (c < y) {",
		"                    return c;",
		"                }",
		"                continue;",
		"            }",
		"",
		"            const uint64_t bit = (x >> (bit_size - depth - 1)) & 1;",
		"",
		"            const uint64_t rank0_begin = this->bit_arrays.at(depth).rank(0, b);",
		"            const uint64_t rank0_end = this->bit_arrays.at(depth).rank(0, e);",
		"            const uint64_t rank1_begin = b - rank0_begin;",
		"            const uint64_t rank1_end = e - rank0_end;",
		"",
		"            // d番目のbitが1のものを使う",
		"            const uint64_t b1 = this->begin_one.at(depth) + rank1_begin;",
		"            const uint64_t e1 = this->begin_one.at(depth) + rank1_end;",
		"            if (b1 != e1) {",
		"                const auto c1 = ((c << 1) | 1);",
		"                s.emplace(std::make_tuple(b1, e1, depth + 1, c1, tight and bit == 1));",
		"            }",
		"",
		"            // d番目のbitが0のものを使う",
		"            const uint64_t b0 = rank0_begin;",
		"            const uint64_t e0 = rank0_end;",
		"            if (b0 != e0) {",
		"                if (not tight or bit == 0) {",
		"                    const uint64_t c0 = ((c << 1) | 0);",
		"                    s.emplace(std::make_tuple(b0, e0, depth + 1, c0, tight));",
		"                }",
		"            }",
		"        }",
		"",
		"        return NOTFOUND;",
		"    }",
		"",
		"    // T[s1, e1)とT[s2, e2)に共通して出現する要素を求める",
		"    std::vector<std::tuple<uint64_t, uint64_t, uint64_t>> intersect(uint64_t _s1, uint64_t _e1, uint64_t _s2, uint64_t _e2) {",
		"        assert(_s1 < _e1);",
		"        assert(_s2 < _e2);",
		"",
		"        std::vector<std::tuple<uint64_t, uint64_t, uint64_t>> intersection;",
		"",
		"        std::queue<std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>> que; // s1, e1, s2, e2, depth, value",
		"        que.push(std::make_tuple(_s1, _e1, _s2, _e2, 0, 0));",
		"        while (not que.empty()) {",
		"            auto e = que.front(); que.pop();",
		"            uint64_t s1, e1, s2, e2, depth, value;",
		"            std::tie(s1, e1, s2, e2, depth, value) = e;",
		"",
		"            if (depth >= this->bit_size) {",
		"                intersection.emplace_back(std::make_tuple(value, e1 - s1, e2 - s2));",
		"                continue;",
		"            }",
		"",
		"            // 0",
		"            uint64_t s1_0 = this->bit_arrays.at(depth).rank(0, s1);",
		"            uint64_t e1_0 = this->bit_arrays.at(depth).rank(0, e1);",
		"            uint64_t s2_0 = this->bit_arrays.at(depth).rank(0, s2);",
		"            uint64_t e2_0 = this->bit_arrays.at(depth).rank(0, e2);",
		"",
		"            if (s1_0 != e1_0 and s2_0 != e2_0) {",
		"                que.push(std::make_tuple(s1_0, e1_0, s2_0, e2_0, depth + 1, value));",
		"            }",
		"",
		"            // 1",
		"            uint64_t s1_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, s1);",
		"            uint64_t e1_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, e1);",
		"            uint64_t s2_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, s2);",
		"            uint64_t e2_1 = this->begin_one.at(depth) + this->bit_arrays.at(depth).rank(1, e2);",
		"",
		"            if (s1_1 != e1_1 and s2_1 != e2_1) {",
		"                que.push(std::make_tuple(s1_1, e1_1, s2_1, e2_1, depth + 1, value | (1 << bit_size - depth - 1)));",
		"            }",
		"        }",
		"",
		"        return intersection;",
		"    };",
		"",
		"private:",
		"    uint64_t get_num_of_bit(uint64_t x) {",
		"        if (x == 0) return 0;",
		"        x--;",
		"        uint64_t bit_num = 0;",
		"        while (x >> bit_num) {",
		"            ++bit_num;",
		"        }",
		"        return bit_num;",
		"    }",
		"",
		"    uint64_t rangeSum(const uint64_t begin, const uint64_t end, const uint64_t depth, const uint64_t c, const uint64_t x, const uint64_t y) {",
		"        if (begin == end) {",
		"            return 0;",
		"        }",
		"",
		"        if (depth == bit_size) {",
		"            if (x <= c and c < y) {",
		"                return c * (end - begin);   // 値 * 頻度",
		"            }",
		"            return 0;",
		"        }",
		"",
		"        const uint64_t next_c = ((uint64_t)1 << (bit_size - depth - 1)) | c;                   // 上からdepth番目のbitを立てる",
		"        const uint64_t all_one_c = (((uint64_t)1 << (bit_size - depth - 1)) - 1) | next_c;     // depth以降のbitをたてる(これ以降全部1を選んだときの値)",
		"        if(all_one_c < x or y <= c) {",
		"            return 0;",
		"        }",
		"",
		"        // [begin, pos)のすべての要素は[x, y)",
		"        if (x <= c and all_one_c < y) {",
		"            return this->cumulative_sum.at(depth).at(end) - this->cumulative_sum.at(depth).at(begin);",
		"        }",
		"",
		"        const uint64_t rank0_begin = this->bit_arrays.at(depth).rank(0, begin);",
		"        const uint64_t rank0_end = this->bit_arrays.at(depth).rank(0, end);",
		"        const uint64_t rank1_begin = begin - rank0_begin;",
		"        const uint64_t rank1_end = end - rank0_end;",
		"",
		"        return rangeSum(rank0_begin, rank0_end, depth + 1, c, x, y) +",
		"               rangeSum(this->begin_one.at(depth) + rank1_begin, this->begin_one[depth] + rank1_end, depth + 1, next_c, x, y);",
		"    }",
		"};",
		"// vector<uint64_t> vec(N);",
		"// WaveletMatrix wm(vec);",
		"// wm.access(i)",
		"// wm.select(val, rank)",
		"// wm.maxRange(left, right)",
		"// wm.minRange(left, right)",
		"// wm.quantileRange(left, right, k)",
		"// wm.rank(right)",
		"// wm.rangeFreq(left, right, min_val, max_val)",
		"// wm.rankLessThan(val, left, right)",
		"// wm.rankMoreThan(val, left, right)",
		"// wm.rankAll(val, left, right)",
		"// wm.topk(left, right, k)",
		"// wm.rangeSum(left, right, val_left, val_right)",
		"// wm.prevValue(left, right, val_left, val_right)",
		"// wm.nextValue(left, right, val_left, val_right)",
		"// wm.intersect(left1, right1, left2, right2)",
		""
		],
		"description": "Wavelet_Matrix"
	},
	//
	//math
	//
	"itertools": {
		"prefix": "atcoder_math_itertools",
		"body": [
		"/**",
		" * @brief nHrの配列を返す",
		" * ",
		" * @tparam T 要素の型",
		" * @param arr 長さnの配列",
		" * @param r 重複組合せで選ぶ数r",
		" * @return vector<vector<T>> nHrの結果を辞書順昇順で返す",
		" */",
		"template<typename T>",
		"vector<vector<T>> combination_with_replacement(vector<T> &arr, int r){",
		"    vector<vector<T>> res;",
		"    function<void(vector<T>&, int)> dfs = [&](vector<T> &e, int idx){",
		"        if ((int)e.size() == r) {",
		"            res.push_back(e);",
		"            return;",
		"        }",
		"        else {",
		"            for(int i = idx; i < (int)arr.size(); i++){",
		"                e.push_back(arr[i]);",
		"                dfs(e, i);",
		"                e.pop_back();",
		"            }",
		"        }",
		"    };",
		"    vector<T> e = {};",
		"    dfs(e, 0);",
		"    return res;",
		"}",
		"",
		"/**",
		" * @brief nCrの配列を返す",
		" * ",
		" * @tparam T 要素の型",
		" * @param arr 長さnの配列",
		" * @param r 組み合わせで選ぶ数r",
		" * @return vector<vector<T>> nCrの結果を辞書順昇順で返す",
		" */",
		"template<typename T>",
		"vector<vector<T>> combinations(vector<T> &arr, int r){",
		"    vector<vector<T>> res;",
		"    int n = arr.size();",
		"    function<void(vector<T>&, int)> dfs = [&](vector<T> &e, int idx){",
		"        if ((int)e.size() == r) {",
		"            res.push_back(e);",
		"            return;",
		"        }",
		"        if (idx == n) return;",
		"",
		"        if (e.size() + (n - (idx + 1)) >= r) dfs(e, idx + 1);",
		"",
		"        e.push_back(arr[idx]);",
		"        if (e.size() + (n - (idx + 1)) >= r) dfs(e, idx + 1);",
		"        e.pop_back();",
		"    };",
		"    vector<T> e = {};",
		"    dfs(e, 0);",
		"    reverse(res.begin(), res.end());",
		"    return res;",
		"}",
		"",
		"/**",
		" * @brief nPrの配列を返す",
		" * ",
		" * @tparam T 要素の型",
		" * @param arr 長さnの配列",
		" * @param r 組み合わせで選ぶ数r",
		" * @param dflag 昇順にソートするならtrue(デフォルトはfalse);",
		" * @return vector<vector<T>> nPrの結果を返す",
		" */",
		"template<typename T>",
		"vector<vector<T>> permutations(vector<T> &arr, int r, bool dflag=false){",
		"    vector<vector<T>> res;",
		"    auto combs = combinations(arr, r);",
		"    for(auto ptn : combs){",
		"        do{",
		"            res.push_back(ptn);",
		"        }while(next_permutation(all(ptn)));",
		"    }",
		"    if(dflag) {",
		"        auto cmp = [](vector<T> &lhs, vector<T> &rhs){",
		"            int nl = lhs.size();",
		"            int nr = rhs.size();",
		"            for(int i = 0; i < min(nl, nr); i++){",
		"                if(lhs[i] == rhs[i]) continue;",
		"                return (lhs[i] < rhs[i]);",
		"            }",
		"            return (nl < nr);",
		"        };",
		"        sort(all(res), cmp);",
		"    }",
		"    return res;",
		"}",
		"",
		"template<typename T>",
		"vector<vector<T>> _productRecurse(vector<T> &choices, int repeat, vector<vector<T>> &result){",
		"    if (repeat == 0) return result;",
		"",
		"    vector<vector<T>> nresult;",
		"    for(vector<T> re : result){",
		"        for(T c : choices){",
		"            vector<T> temp = re;",
		"            temp.push_back(c);",
		"            nresult.push_back(temp);",
		"        }",
		"    }",
		"",
		"    return _productRecurse(choices, repeat - 1, nresult);",
		"}",
		"",
		"/**",
		" * @brief 直積を返す ",
		" * ",
		" * @tparam T 要素の型",
		" * @param arr 長さnの配列",
		" * @param r 冪乗",
		" * @return vector<vector<T>> product({0, 1, 2}, 2) -> {{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}",
		" */",
		"template<typename T>",
		"vector<vector<T>> product(vector<T> &arr, int r=1){",
		"    vector<vector<T>> emptyResult(1, vector<T>{});",
		"    return _productRecurse(arr, r, emptyResult);",
		"}",
		""
		],
		"description": "itertools"
	},
	"python_like": {
		"prefix": "atcoder_math_python_like",
		"body": [
		"// a // b in Python",
		"template<typename T>",
		"T floor(T a, T b){",
		"    if (a >= 0) return a / b;",
		"    else {",
		"        if (abs(a) % b == 0){",
		"            return a/b;",
		"        }",
		"        else{",
		"            return a/b-1;",
		"        }",
		"    }",
		"}",
		"",
		"// a % b in Python",
		"template<typename T>",
		"T div_mod(T a, T b){",
		"    if (a >= 0) return a % b;",
		"    else{",
		"        if (abs(a) % b == 0){",
		"            return 0;",
		"        }",
		"        else{",
		"            return b - abs(a) % b;",
		"        }",
		"    }",
		"}",
		""
		],
		"description": "python_like"
	},
	"fps": {
		"prefix": "atcoder_math_fps",
		"body": [
		"//形式的冪級数",
		"//https://qiita.com/gg_hatano/items/3591ddf267092c235a23",
		"#define rep2(i, m, n) for (int i = (m); i < (n); ++i)",
		"#define drep2(i, m, n) for (int i = (m)-1; i >= (n); --i)",
		"#define drep(i, n) drep2(i, n, 0)",
		"template<class T>",
		"struct FormalPowerSeries : vector<T> {",
		"    using vector<T>::vector;",
		"    using vector<T>::operator=;",
		"    using F = FormalPowerSeries;",
		" ",
		"    F operator-() const {",
		"        F res(*this);",
		"        for (auto &e : res) e = -e;",
		"        return res;",
		"    }",
		"    F &operator*=(const T &g) {",
		"        for (auto &e : *this) e *= g;",
		"        return *this;",
		"    }",
		"    F &operator/=(const T &g) {",
		"        assert(g != T(0));",
		"        *this *= g.inv();",
		"        return *this;",
		"    }",
		"    F &operator+=(const F &g) {",
		"        int n = (*this).size(), m = g.size();",
		"        rep(i, min(n, m)) (*this)[i] += g[i];",
		"        return *this;",
		"    }",
		"    F &operator-=(const F &g) {",
		"        int n = (*this).size(), m = g.size();",
		"        rep(i, min(n, m)) (*this)[i] -= g[i];",
		"        return *this;",
		"    }",
		"    F &operator<<=(const int d) {",
		"        int n = (*this).size();",
		"        (*this).insert((*this).begin(), d, 0);",
		"        (*this).resize(n);",
		"        return *this;",
		"    }",
		"    F &operator>>=(const int d) {",
		"        int n = (*this).size();",
		"        (*this).erase((*this).begin(), (*this).begin() + min(n, d));",
		"        (*this).resize(n);",
		"        return *this;",
		"    }",
		"    F inv(int d = -1) const {",
		"        int n = (*this).size();",
		"        assert(n != 0 && (*this)[0] != 0);",
		"        if (d == -1) d = n;",
		"        assert(d > 0);",
		"        F res{(*this)[0].inv()};",
		"        while (res.size() < d) {",
		"            int m = size(res);",
		"            F f(begin(*this), begin(*this) + min(n, 2*m));",
		"            F r(res);",
		"            f.resize(2*m), internal::butterfly(f);",
		"            r.resize(2*m), internal::butterfly(r);",
		"            rep(i, 2*m) f[i] *= r[i];",
		"            internal::butterfly_inv(f);",
		"            f.erase(f.begin(), f.begin() + m);",
		"            f.resize(2*m), internal::butterfly(f);",
		"            rep(i, 2*m) f[i] *= r[i];",
		"            internal::butterfly_inv(f);",
		"            T iz = T(2*m).inv(); iz *= -iz;",
		"            rep(i, m) f[i] *= iz;",
		"            res.insert(res.end(), f.begin(), f.begin() + m);",
		"        }",
		"        return {res.begin(), res.begin() + d};",
		"    }",
		" ",
		"    // fast: FMT-friendly modulus only",
		"    F &operator*=(const F &g) {",
		"        int n = (*this).size();",
		"        *this = convolution(*this, g);",
		"        (*this).resize(n);",
		"        return *this;",
		"    }",
		"    F &operator/=(const F &g) {",
		"        int n = (*this).size();",
		"        *this = convolution(*this, g.inv(n));",
		"        (*this).resize(n);",
		"        return *this;",
		"    }",
		" ",
		"    // // naive",
		"    // F &operator*=(const F &g) {",
		"    //   int n = (*this).size(), m = g.size();",
		"    //   drep(i, n) {",
		"    //     (*this)[i] *= g[0];",
		"    //     rep2(j, 1, min(i+1, m)) (*this)[i] += (*this)[i-j] * g[j];",
		"    //   }",
		"    //   return *this;",
		"    // }",
		"    // F &operator/=(const F &g) {",
		"    //   assert(g[0] != T(0));",
		"    //   T ig0 = g[0].inv();",
		"    //   int n = (*this).size(), m = g.size();",
		"    //   rep(i, n) {",
		"    //     rep2(j, 1, min(i+1, m)) (*this)[i] -= (*this)[i-j] * g[j];",
		"    //     (*this)[i] *= ig0;",
		"    //   }",
		"    //   return *this;",
		"    // }",
		" ",
		"    // sparse",
		"    F &operator*=(vector<pair<int, T>> g) {",
		"        int n = (*this).size();",
		"        auto [d, c] = g.front();",
		"        if (d == 0) g.erase(g.begin());",
		"        else c = 0;",
		"        drep(i, n) {",
		"            (*this)[i] *= c;",
		"            for (auto &[j, b] : g) {",
		"                if (j > i) break;",
		"                (*this)[i] += (*this)[i-j] * b;",
		"            }",
		"        }",
		"        return *this;",
		"    }",
		"    F &operator/=(vector<pair<int, T>> g) {",
		"        int n = (*this).size();",
		"        auto [d, c] = g.front();",
		"        assert(d == 0 && c != T(0));",
		"        T ic = c.inv();",
		"        g.erase(g.begin());",
		"        rep(i, n) {",
		"            for (auto &[j, b] : g) {",
		"            if (j > i) break;",
		"              (*this)[i] -= (*this)[i-j] * b;",
		"            }",
		"            (*this)[i] *= ic;",
		"        }",
		"        return *this;",
		"    }",
		" ",
		"    // multiply and divide (1 + cz^d)",
		"    void multiply(const int d, const T c) { ",
		"        int n = (*this).size();",
		"        if (c == T(1)) drep(i, n-d) (*this)[i+d] += (*this)[i];",
		"        else if (c == T(-1)) drep(i, n-d) (*this)[i+d] -= (*this)[i];",
		"        else drep(i, n-d) (*this)[i+d] += (*this)[i] * c;",
		"    }",
		"    void divide(const int d, const T c) {",
		"        int n = (*this).size();",
		"        if (c == T(1)) rep(i, n-d) (*this)[i+d] -= (*this)[i];",
		"        else if (c == T(-1)) rep(i, n-d) (*this)[i+d] += (*this)[i];",
		"        else rep(i, n-d) (*this)[i+d] -= (*this)[i] * c;",
		"    }",
		" ",
		"    T eval(const T &a) const {",
		"        T x(1), res(0);",
		"        for (auto e : *this) res += e * x, x *= a;",
		"        return res;",
		"    }",
		" ",
		"    F operator*(const T &g) const { return F(*this) *= g; }",
		"    F operator/(const T &g) const { return F(*this) /= g; }",
		"    F operator+(const F &g) const { return F(*this) += g; }",
		"    F operator-(const F &g) const { return F(*this) -= g; }",
		"    F operator<<(const int d) const { return F(*this) <<= d; }",
		"    F operator>>(const int d) const { return F(*this) >>= d; }",
		"    F operator*(const F &g) const { return F(*this) *= g; }",
		"    F operator/(const F &g) const { return F(*this) /= g; }",
		"    F operator*(vector<pair<int, T>> g) const { return F(*this) *= g; }",
		"    F operator/(vector<pair<int, T>> g) const { return F(*this) /= g; }",
		"};",
		"using mint = modint998244353;",
		"using fps = FormalPowerSeries<mint>;",
		"using sfps = vector<pair<int, mint>>; // (次数,係数)",
		" "
		],
		"description": "fps"
	},
	"arbitrary": {
		"prefix": "atcoder_math_cmb_arbitrary",
		"body": [
		"struct Barrett {",
		"  using u32 = unsigned int;",
		"  using i64 = long long;",
		"  using u64 = unsigned long long;",
		"  u32 m;",
		"  u64 im;",
		"  Barrett() : m(), im() {}",
		"  Barrett(int n) : m(n), im(u64(-1) / m + 1) {}",
		"  constexpr inline i64 quo(u64 n) {",
		"    u64 x = u64((__uint128_t(n) * im) >> 64);",
		"    u32 r = n - x * m;",
		"    return m <= r ? x - 1 : x;",
		"  }",
		"  constexpr inline i64 rem(u64 n) {",
		"    u64 x = u64((__uint128_t(n) * im) >> 64);",
		"    u32 r = n - x * m;",
		"    return m <= r ? r + m : r;",
		"  }",
		"  constexpr inline pair<i64, int> quorem(u64 n) {",
		"    u64 x = u64((__uint128_t(n) * im) >> 64);",
		"    u32 r = n - x * m;",
		"    if (m <= r) return {x - 1, r + m};",
		"    return {x, r};",
		"  }",
		"  constexpr inline i64 pow(u64 n, i64 p) {",
		"    u32 a = rem(n), r = m == 1 ? 0 : 1;",
		"    while (p) {",
		"      if (p & 1) r = rem(u64(r) * a);",
		"      a = rem(u64(a) * a);",
		"      p >>= 1;",
		"    }",
		"    return r;",
		"  }",
		"};",
		"",
		"#define PRIME_POWER_BINOMIAL_M_MAX ((1LL << 30) - 1)",
		"#define PRIME_POWER_BINOMIAL_N_MAX 20000000",
		"",
		"struct prime_power_binomial {",
		"  int p, q, M;",
		"  vector<int> fac, ifac, inv;",
		"  int delta;",
		"  Barrett bm, bp;",
		"",
		"  prime_power_binomial(int _p, int _q) : p(_p), q(_q) {",
		"    assert(1 < p && p <= PRIME_POWER_BINOMIAL_M_MAX);",
		"    assert(_q > 0);",
		"    long long m = 1;",
		"    while (_q--) {",
		"      m *= p;",
		"      assert(m <= PRIME_POWER_BINOMIAL_M_MAX);",
		"    }",
		"    M = m;",
		"    bm = Barrett(M), bp = Barrett(p);",
		"    enumerate();",
		"    delta = (p == 2 && q >= 3) ? 1 : M - 1;",
		"  }",
		"",
		"  void enumerate() {",
		"    int MX = min<int>(M, PRIME_POWER_BINOMIAL_N_MAX + 10);",
		"    fac.resize(MX);",
		"    ifac.resize(MX);",
		"    inv.resize(MX);",
		"    fac[0] = ifac[0] = inv[0] = 1;",
		"    fac[1] = ifac[1] = inv[1] = 1;",
		"    for (int i = 2; i < MX; i++) {",
		"      if (i % p == 0) {",
		"        fac[i] = fac[i - 1];",
		"        fac[i + 1] = bm.rem(1LL * fac[i - 1] * (i + 1));",
		"        i++;",
		"      } else {",
		"        fac[i] = bm.rem(1LL * fac[i - 1] * i);",
		"      }",
		"    }",
		"    ifac[MX - 1] = bm.pow(fac[MX - 1], M / p * (p - 1) - 1);",
		"    for (int i = MX - 2; i > 1; --i) {",
		"      if (i % p == 0) {",
		"        ifac[i] = bm.rem(1LL * ifac[i + 1] * (i + 1));",
		"        ifac[i - 1] = ifac[i];",
		"        i--;",
		"      } else {",
		"        ifac[i] = bm.rem(1LL * ifac[i + 1] * (i + 1));",
		"      }",
		"    }",
		"  }",
		"",
		"  long long Lucas(long long n, long long m) {",
		"    int res = 1;",
		"    while (n) {",
		"      int n0, m0;",
		"      tie(n, n0) = bp.quorem(n);",
		"      tie(m, m0) = bp.quorem(m);",
		"      if (n0 < m0) return 0;",
		"      res = bm.rem(1LL * res * fac[n0]);",
		"      int buf = bm.rem(1LL * ifac[n0 - m0] * ifac[m0]);",
		"      res = bm.rem(1LL * res * buf);",
		"    }",
		"    return res;",
		"  }",
		"",
		"  long long C(long long n, long long m) {",
		"    if (n < m || n < 0 || m < 0) return 0;",
		"    if (q == 1) return Lucas(n, m);",
		"    long long r = n - m;",
		"    int e0 = 0, eq = 0, i = 0;",
		"    int res = 1;",
		"    while (n) {",
		"      res = bm.rem(1LL * res * fac[bm.rem(n)]);",
		"      res = bm.rem(1LL * res * ifac[bm.rem(m)]);",
		"      res = bm.rem(1LL * res * ifac[bm.rem(r)]);",
		"      n = bp.quo(n);",
		"      m = bp.quo(m);",
		"      r = bp.quo(r);",
		"      int eps = n - m - r;",
		"      e0 += eps;",
		"      if (e0 >= q) return 0;",
		"      if (++i >= q) eq += eps;",
		"    }",
		"    if (eq & 1) res = bm.rem(1LL * res * delta);",
		"    res = bm.rem(1LL * res * bm.pow(p, e0));",
		"    return res;",
		"  }",
		"};",
		"",
		"// constraints:",
		"// (M <= 1e7 and max(N) <= 1e18) or (M < 2^30 and max(N) <= 2e7)",
		"struct arbitrary_mod_binomial {",
		"  int mod;",
		"  vector<int> M;",
		"  vector<prime_power_binomial> cs;",
		"",
		"  arbitrary_mod_binomial(long long md) : mod(md) {",
		"    assert(1 <= md);",
		"    assert(md <= PRIME_POWER_BINOMIAL_M_MAX);",
		"    for (int i = 2; i * i <= md; i++) {",
		"      if (md % i == 0) {",
		"        int j = 0, k = 1;",
		"        while (md % i == 0) md /= i, j++, k *= i;",
		"        M.push_back(k);",
		"        cs.emplace_back(i, j);",
		"        assert(M.back() == cs.back().M);",
		"      }",
		"    }",
		"    if (md != 1) {",
		"      M.push_back(md);",
		"      cs.emplace_back(md, 1);",
		"    }",
		"    assert(M.size() == cs.size());",
		"  }",
		"",
		"  long long C(long long n, long long m) {",
		"    if (mod == 1) return 0;",
		"    vector<long long> rem, d;",
		"    for (int i = 0; i < (int)cs.size(); i++) {",
		"      rem.push_back(cs[i].C(n, m));",
		"      d.push_back(M[i]);",
		"    }",
		"    return atcoder::crt(rem, d).first;",
		"  }",
		"};",
		"",
		"#undef PRIME_POWER_BINOMIAL_M_MAX",
		"#undef PRIME_POWER_BINOMIAL_N_MAX",
		"",
		"/**",
		" * @brief 任意mod二項係数",
		" * @docs docs/modulo/arbitrary-mod-binomial.md",
		" */",
		"// arbitrary_mod_binomial coef(MOD);",
		"// coef.C(N,K);",
		""
		],
		"description": "arbitrary"
	},
	"combination": {
		"prefix": "atcoder_math_cmb",
		"body": [
		"//https://drken1215.hatenablog.com/entry/2018/06/08/210000",
		"//COMinit()を忘れない!!!",
		"const ll NMAX = 202020;",
		"const ll MOD = 998244353;",
		"//const int MOD = 1e9+7;",
		"",
		"ll fac[NMAX],finv[NMAX],inv[NMAX];",
		"",
		"void COMinit(){",
		"    fac[0] = fac[1] = 1LL;",
		"    finv[0] = finv[1] = 1LL;",
		"    inv[1] = 1LL;",
		"    for (int i=2;i<NMAX;i++){",
		"        fac[i] = fac[i-1] * i % MOD;",
		"        inv[i] = MOD - inv[MOD%i] * (MOD/i) % MOD;",
		"        finv[i] = finv[i-1] * inv[i] % MOD;",
		"    }",
		"}",
		"",
		"ll nCr(int n,int k){",
		"    if (n<k) return 0LL;",
		"    if (n < 0 || k < 0) return 0LL;",
		"    return fac[n] * (finv[k] * finv[n-k] % MOD) % MOD;",
		"}",
		"",
		"ll nPr(int n,int k){",
		"    if (n<k) return 0LL;",
		"    if (n < 0 || k < 0) return 0LL;",
		"    return fac[n] * finv[n-k] % MOD;",
		"}",
		"",
		"ll nHr(int n,int r){",
		"    return nCr(n+r-1,r);",
		"}"
		],
		"description": "combination"
	},
	"matrix_skeir": {
		"prefix": "atcoder_math_matrix_skeir",
		"body": [
		"mat mat_mul(mat &A, mat &B) {",
		"    mat C(A.size(), vector<ll>(B[0].size()));",
		"    for (int i = 0; i < A.size(); ++i) {",
		"        for (int k = 0; k < B.size(); k++) {",
		"            for (int j = 0; j < B[0].size(); j++) {",
		"                C[i][j] = (C[i][j] + (A[i][k] * B[k][j]) % M) % M;",
		"            }",
		"        }",
		"    }",
		"    return C;",
		"}",
		"",
		"mat mat_pow(mat &A, ll k) {",
		"    mat res(A.size(), vector<ll>(A.size()));",
		"    for (int i = 0; i < res.size(); i++) {",
		"        res[i][i] = 1;",
		"    }",
		"    while (k > 0) {",
		"        if (k & 1) res = mat_mul(res, A);",
		"        A = mat_mul(A, A);",
		"        k >>= 1;",
		"    }",
		"    return res;",
		"}"
		],
		"description": "matrix_skeir"
	},
	"matrix": {
		"prefix": "atcoder_math_matrix",
		"body": [
		"// https://youtu.be/ylWYSurx10A?t=2352",
		"template<typename T>",
		"struct Matrix{",
		"    int h, w;",
		"    vector<vector<T>> d;",
		"    Matrix(): h(0), w(0) {}",
		"    Matrix(int h, int w, T val=0): h(h), w(w), d(h, vector<T>(w,val)) {}",
		"    Matrix(int n, T val=0): h(n), w(n), d(n, vector<T>(n,val)) {}",
		"",
		"    Matrix& unit(){",
		"        assert(h == w);",
		"        rep(i,h) d[i][i] = 1;",
		"        return *this;",
		"    }",
		"",
		"    const vector<T>& operator[](int i) const { return d[i];}",
		"    vector<T>& operator[](int i) { return d[i];}",
		"",
		"    Matrix operator+(const Matrix& a) const {",
		"        assert(h == a.h && w == a.w);",
		"        Matrix r(h, w);",
		"        rep(i,h)rep(j,w){",
		"            r[i][j] = d[i][j] + a[i][j];",
		"        }",
		"        return r;",
		"    }",
		"",
		"    Matrix &operator+=(const Matrix& a) const {",
		"        assert(h == a.h && w == a.w);",
		"        rep(i,h)rep(j,w){",
		"            (*this)[i][j] += a[i][j];",
		"        }",
		"        return (*this);",
		"    }",
		"",
		"    Matrix operator-(const Matrix& a) const {",
		"        assert(h == a.h && w == a.w);",
		"        Matrix r(h, w);",
		"        rep(i,h)rep(j,w){",
		"            r[i][j] = d[i][j] - a[i][j];",
		"        }",
		"        return r;",
		"    }",
		"",
		"    Matrix &operator-=(const Matrix& a) const {",
		"        assert(h == a.h && w == a.w);",
		"        rep(i,h)rep(j,w){",
		"            (*this)[i][j] -= a[i][j];",
		"        }",
		"        return (*this);",
		"    }",
		"",
		"    Matrix operator*(const Matrix& a) const {",
		"        assert(w == a.h);",
		"        Matrix r(h, a.w);",
		"        rep(i,h)rep(k,w)rep(j,a.w){",
		"            r[i][j] += d[i][k] * a[k][j];",
		"        }",
		"        return r;",
		"    }",
		"",
		"    Matrix &operator*=(const Matrix& a) const {",
		"        assert(w == a.h);",
		"        vector<vector<T>> nd(h, vector<T>(w));",
		"        rep(i,h)rep(k,w)rep(j,a.w){",
		"            nd[i][j] += (*this)[i][k] * a[k][j];",
		"        }",
		"        d = move(nd);",
		"        return (*this);",
		"    }",
		"",
		"    vector<T> operator*(const vector<T> &a) const {",
		"        // res[i] = sum{ M[i][j] * x[j] } (j = 0 ... h-1)",
		"        assert(w == (int)a.size());",
		"        vector<T> r(h);",
		"        rep(i,h)rep(j,w){",
		"            r[i] += (*this)[i][j] * a[j];",
		"        }",
		"        return r;",
		"    }",
		"",
		"    Matrix operator*(const T &a) const {",
		"        Matrix r(h, w);",
		"        rep(i,h)rep(j,w){",
		"            r[i][j] = (*this)[i][j] * a;",
		"        }",
		"        return r;",
		"    }",
		"",
		"    Matrix &operator*=(const T &a) const {",
		"        vector<vector<T>> nd(h, vector<T>(w));",
		"        rep(i,h)rep(j,w){",
		"            nd[i][j] = (*this)[i][j] * a;",
		"        }",
		"        d = move(nd);",
		"        return (*this);",
		"    }",
		"",
		"    bool operator==(const Matrix &a){",
		"        if(h != a.h || w != a.w) return false;",
		"        rep(i,h)rep(j,w){",
		"            if((*this)[i][j] != a[i][j]) return false;",
		"        }",
		"        return true;",
		"    }",
		"",
		"    friend ostream &operator<<(ostream &os, Matrix &a){",
		"        rep(i,a.h){",
		"            os << (i == 0 ? '[' : ' ');",
		"            rep(j,a.w) os << (j == 0 ? '[' : ' ') << a[i][j] << (j == a.w - 1 ? \"]\" : \",\");",
		"            os << (i == a.h - 1 ? \"]\" : \",\") << '\\n';",
		"        }",
		"        return os;",
		"    }",
		"",
		"",
		"    pair<int, int> shape() {return {this->h, this->w};}",
		"",
		"    static Matrix eye(int n){",
		"        Matrix mat(n, n);",
		"        mat.unit();",
		"        return mat;",
		"    }",
		"",
		"    Matrix pow(long long t) const {",
		"        assert(h == w);",
		"        if(!t) Matrix(h, h).unit();",
		"        if(t == 1) return *this;",
		"        Matrix r = pow(t >> 1);",
		"        r = r * r;",
		"        if(t & 1) r = r * (*this);",
		"        return r;",
		"    }",
		"",
		"    T det(){",
		"        assert(h == w);",
		"        vector<vector<T>> dc = d;",
		"        T res = 1;",
		"        rep(k,h){",
		"            for(int i = k; i < h; i++){",
		"                if(dc[i][k] == 0) continue;",
		"                if(i != k){",
		"                    swap(dc[i], dc[k]);",
		"                    res = -res;",
		"                }",
		"            }",
		"            if(dc[k][k] == 0) return 0;",
		"            res *= dc[k][k];",
		"            T inv = T(1) / dc[k][k];",
		"            rep(j,h) dc[k][j] *= inv;",
		"            for(int i = k + 1; i < h; i++){",
		"                T c = dc[i][k];",
		"                for(int j = k; j < h; j++) dc[i][j] -= dc[k][j] * c;",
		"            }",
		"        }",
		"        return res;",
		"    }",
		"",
		"    Matrix inv(){",
		"        assert(h == w);",
		"        int n = h;",
		"        // (A E) -> (E, invA)",
		"        Matrix AE(n, 2 * n);",
		"        rep(i,n){",
		"            rep(j,n) AE[i][j] = d[i][j];",
		"            AE[i][i + n] = 1;",
		"        }",
		"",
		"        rep(r, n){",
		"            int pivot = -1;",
		"            for(int i = r; i < n; i++){",
		"                if(AE[i][r] != 0){",
		"                    pivot = i;",
		"                    break;",
		"                }",
		"            }",
		"            // 逆行列が存在しない",
		"            if(pivot == -1) return Matrix();",
		"            swap(AE[r], AE[pivot]);",
		"",
		"            for(int j = r + 1; j < 2 * n; j++) AE[r][j] /= AE[r][r];",
		"            rep(i,n)if(i != r){",
		"                for(int j = r + 1; j < 2 * n; j++){",
		"                    AE[i][j] -= AE[i][r] * AE[r][j];",
		"                }",
		"            }",
		"        }",
		"",
		"        Matrix r(n, n);",
		"        rep(i,n)rep(j,n) r[i][j] = AE[i][j + n];",
		"        return r;",
		"    }",
		"",
		"    // !! not verify !!",
		"    vector<T> linear_equation(vector<T> b){",
		"        Matrix invA = (*this).inv();",
		"        if(invA.h == 0) return {};",
		"        return invA * b;",
		"    }",
		"};",
		"",
		"// Matrix<T> mat(h, w);",
		"// Matrix<T> identity = Matrix<T>::eye(n);",
		"// pii hw = mat.shape();",
		"// T determinant = A.det();",
		"// Matrix<T> powA = A.pow(K);",
		"// Matrix<T> invA = A.pow(K);",
		"// vector<T> x = A.linear_equation(b);",
		""
		],
		"description": "matrix"
	},
	"Millar_Rabin": {
		"prefix": "atcoder_math_Miller_Rabin",
		"body": [
		"// A ^ N を M で割ったあまり",
		"template<class T> T pow_mod(T A, T N, T M) {",
		"    T res = 1 % M;",
		"    A %= M;",
		"    while (N) {",
		"        if (N & 1) res = (res * A) % M;",
		"        A = (A * A) % M;",
		"        N >>= 1;",
		"    }",
		"    return res;",
		"}",
		"",
		"// Miller-Rabin 素数判定",
		"bool Miller_Rabin(long long N) {",
		"    if (N <= 1) return false;",
		"    if (N == 2) return true;",
		"    if (N % 2 == 0) return false;",
		"    vector<long long> A = {2, 325, 9375, 28178, 450775,",
		"                           9780504, 1795265022};",
		"    long long s = 0, d = N - 1;",
		"    while (d % 2 == 0) {",
		"        ++s;",
		"        d >>= 1;",
		"    }",
		"    for (auto a : A) {",
		"        if (a % N == 0) return true;",
		"        long long t, x = pow_mod<__int128_t>(a, d, N);",
		"        if (x != 1) {",
		"            for (t = 0; t < s; ++t) {",
		"                if (x == N - 1) break;",
		"                x = __int128_t(x) * x % N;",
		"            }",
		"            if (t == s) return false;",
		"        }",
		"    }",
		"    return true;",
		"}",
		""
		],
		"description": "Millar_Rabin"
	},
	"math": {
		"prefix": "atcoder_math_Pollard",
		"body": [
		"// https://algo-method.com/tasks/553/editorial",
		"// Miller-Rabin 素数判定法",
		"template<class T> T pow_mod(T A, T N, T M) {",
		"    T res = 1 % M;",
		"    A %= M;",
		"    while (N) {",
		"        if (N & 1) res = (res * A) % M;",
		"        A = (A * A) % M;",
		"        N >>= 1;",
		"    }",
		"    return res;",
		"}",
		"",
		"bool is_prime(long long N) {",
		"    if (N <= 1) return false;",
		"    if (N == 2 || N == 3) return true;",
		"    if (N % 2 == 0) return false;",
		"    vector<long long> A = {2, 325, 9375, 28178, 450775,",
		"                           9780504, 1795265022};",
		"    long long s = 0, d = N - 1;",
		"    while (d % 2 == 0) {",
		"        ++s;",
		"        d >>= 1;",
		"    }",
		"    for (auto a : A) {",
		"        if (a % N == 0) return true;",
		"        long long t, x = pow_mod<__int128_t>(a, d, N);",
		"        if (x != 1) {",
		"            for (t = 0; t < s; ++t) {",
		"                if (x == N - 1) break;",
		"                x = __int128_t(x) * x % N;",
		"            }",
		"            if (t == s) return false;",
		"        }",
		"    }",
		"    return true;",
		"}",
		"",
		"// Pollard のロー法",
		"long long gcd(long long A, long long B) {",
		"    A = abs(A), B = abs(B);",
		"    if (B == 0) return A;",
		"    else return gcd(B, A % B);",
		"}",
		"    ",
		"long long pollard(long long N) {",
		"    if (N % 2 == 0) return 2;",
		"    if (is_prime(N)) return N;",
		"",
		"    auto f = [&](long long x) -> long long {",
		"        return (__int128_t(x) * x + 1) % N;",
		"    };",
		"    long long step = 0;",
		"    while (true) {",
		"        ++step;",
		"        long long x = step, y = f(x);",
		"        while (true) {",
		"            long long p = gcd(y - x + N, N);",
		"            if (p == 0 || p == N) break;",
		"            if (p != 1) return p;",
		"            x = f(x);",
		"            y = f(f(y));",
		"        }",
		"    }",
		"}",
		"",
		"vector<long long> prime_factorize(long long N) {",
		"    if (N == 1) return {};",
		"    long long p = pollard(N);",
		"    if (p == N) return {p};",
		"    vector<long long> left = prime_factorize(p);",
		"    vector<long long> right = prime_factorize(N / p);",
		"    left.insert(left.end(), right.begin(), right.end());",
		"    sort(left.begin(), left.end());",
		"    return left;",
		"}",
		""
		],
		"description": "math"
	},
	"is_prime": {
		"prefix": "atcoder_math_isprime",
		"body": [
		"//O(sqrt(N))",
		"bool is_prime(ll n){",
		"    for(ll i=2;i*i<=n;i++){",
		"        if (n % i == 0) return false;",
		"    }",
		"    return true;",
		"}",
		""
		],
		"description": "is_prime"
	},
	"euler_phi": {
		"prefix": "atcoder_math_euler_phi",
		"body": [
		"",
		"ll euler_phi(ll n){",
		"    ll res = n;",
		"    for(ll i = 2; i * i <= n; i++){",
		"        if (n % i) continue;",
		"        res = res - res / i;",
		"        while((n % i) == 0) n /= i;",
		"    }",
		"    if (n != 1) res = res - res / n;",
		"    return res;",
		"}",
		""
		],
		"description": "euler_phi"
	},
	"Eratosthenes": {
		"prefix": "atcoder_math_Eratosthenes",
		"body": [
		"// https://qiita.com/drken/items/3beb679e54266f20ab63",
		"struct Eratosthenes{",
		"    int N;",
		"    vector<bool> isprime;",
		"    vector<int> minfactor, mobius;",
		"    Eratosthenes(int N_max = 1e7){init(N_max);}",
		"    //初期化",
		"    void init(int N_max = 1e7){",
		"        int N = N_max;",
		"        isprime.assign(N+1,true);",
		"        minfactor.assign(N+1,-1);",
		"        mobius.assign(N+1,1);",
		"        //Eratosthenes O(NloglogN)",
		"        isprime[0] = false;",
		"        isprime[1] = false;",
		"        for(int p=2;p<=N;p++){",
		"            if (!isprime[p])continue;",
		"            minfactor[p] = p;",
		"            mobius[p] = -1;",
		"            //pの倍数の処理",
		"            for(int q=2*p;q<=N;q+=p){",
		"                isprime[q] = false;",
		"                if (minfactor[q] == -1){",
		"                    minfactor[q] = p;",
		"                }",
		"                if ((q/p) % p == 0) mobius[q] = 0;",
		"                else mobius[q] *= -1;",
		"            }",
		"        }",
		"    }",
		"    //素数判定,O(1)",
		"    bool judge_prime(int num){",
		"        return isprime[num];",
		"    }",
		"    //素数列挙,O(N)",
		"    vector<int> list_primes(int num = -1){",
		"        if (num == -1) num = N;",
		"        vector<int> primes;",
		"        for(int p=0;p<=num;p++){",
		"            if (isprime[p]) primes.push_back(p);",
		"        }",
		"        return primes;",
		"    }",
		"    //高速素因数分解,O(logN),{(素因数,個数)...}",
		"    vector<pii> factorize(int x){",
		"        vector<pii> ans;",
		"        while(x > 1){",
		"            int p = minfactor[x];",
		"            int e = 0;",
		"            while(minfactor[x] == p){",
		"                x /= p;",
		"                e++;",
		"            }",
		"            ans.push_back(make_pair(p,e));",
		"        }",
		"        return ans;",
		"    }",
		"    //高速約数列挙 O(240(N <= 1e6),1344(N <= 1e9))",
		"    vector<int> divisors(int x){",
		"        vector<int> ans; ans.push_back(1);",
		"        vector<pii> facts = factorize(x);",
		"        for(auto [p,e]:facts){",
		"            int s = ans.size();",
		"            for(int i=0;i<s;i++){",
		"                int v = 1;",
		"                for(int j=0;j<e;j++){",
		"                    v *= p;",
		"                    ans.push_back(ans[i] * v);",
		"                }",
		"            }",
		"        }",
		"        sort(all(ans));",
		"        return ans;",
		"    }",
		"    //オイラーのphi関数",
		"    ll euler_phi(int x){",
		"        auto facts = factorize(x);",
		"        ll res = x;",
		"        for(auto [p, e]:facts){",
		"            res = res - res / p;",
		"        }",
		"        return res;",
		"    }",
		"    //メビウス関数",
		"    //mobius[1] = 1",
		"    //nが素数pで2回以上割り切れる -> mobius[n] = 0",
		"    //mobius[n] = pow(-1,Nの素数の種類)",
		"    int my_mobius(int x){",
		"        return mobius[x];",
		"    }",
		"};",
		"",
		"// f -> F, 累積和Fを求める",
		"template<typename T>",
		"vector<T> fast_zeta(vector<T> &f){",
		"    vector<T> res = f;",
		"    int N = f.size() - 1; ",
		"    Eratosthenes er(N);",
		"    for(int p=2;p<=N;p++){",
		"        if (!er.judge_prime(p)) continue;",
		"        for(int k=(N/p);k>0;k--){",
		"            res[k] += res[k * p];",
		"        }",
		"    }",
		"    return res;",
		"}",
		"",
		"// F -> f, 累積和Fを分解する",
		"template<typename T>",
		"vector<T> fast_mobius(vector<T> &F){",
		"    vector<T> res = F;",
		"    int N = F.size() - 1; ",
		"    Eratosthenes er(N);",
		"    for(int p=2;p<=N;p++){",
		"        if (!er.judge_prime(p)) continue;",
		"        for(int k=1;k<=(N/p);k++){",
		"            res[k] -= res[k * p];",
		"        }",
		"    }",
		"    return res;",
		"}",
		"",
		"template<typename T>",
		"vector<T> gcd_conv(vector<T> &f, vector<T> &g){",
		"    int N = max(f.size(), g.size());",
		"    vector<T> F(N+1) , G(N+1), H(N+1);",
		"    for(int i=0;i<f.size();i++){",
		"        F[i] = f[i];",
		"    }",
		"    for(int i=0;i<g.size();i++){",
		"        G[i] = g[i];",
		"    }",
		"    F = fast_zeta(F);",
		"    G = fast_zeta(G);",
		"    for(int i=1;i<=N;i++){",
		"        H[i] = F[i] * G[i];",
		"    }",
		"    H = fast_mobius(H);",
		"    return H;",
		"}",
		""
		],
		"description": "Eratosthenes"
	},
	"factorize": {
		"prefix": "atcoder_math_factorize",
		"body": [
		"vector<pll> prime_factorize(ll n){",
		"    vector<pll> res;",
		"    for(ll i = 2; i * i <= n ; i++){",
		"        if(n % i != 0ll)continue;",
		"        ll tmp = 0ll;",
		"        while(n % i == 0ll){",
		"            tmp++;",
		"            n /= i;",
		"        }",
		"        res.push_back(make_pair(i,tmp));",
		"    }",
		"    if (n != 1ll) res.push_back(make_pair(n,1ll));",
		"    return res;",
		"}",
		""
		],
		"description": "factorize"
	},
	"make_divisors": {
		"prefix": "atcoder_math_divisors",
		"body": [
		"vector<ll> make_divisors(ll n){",
		"    vector<ll> divisors;",
		"    ll i = 1;",
		"    while (i * i <= n){",
		"        if (n % i == 0){",
		"            divisors.push_back(i);",
		"            if (i != (n/i)) divisors.push_back(n/i);",
		"        }",
		"        i++;",
		"    }",
		"    sort(all(divisors));",
		"    return divisors;",
		"}",
		""
		],
		"description": "make_divisors"
	},
	"modpow": {
		"prefix": "atcoder_math_modpow",
		"body": [
		"long long modpow(long long x, long long n, long long MOD) {",
		"    long long ret = 1;",
		"    while (n > 0) {",
		"        if (n & 1) ret = ret * x % MOD;  // n の最下位bitが 1 ならば x^(2^i) をかける",
		"        x = x * x % MOD;",
		"        n >>= 1;  // n を1bit 左にずらす",
		"    }",
		"    return ret;",
		"}",
		""
		],
		"description": "modpow"
	},
	//
	// graph theory
	//
	"dijkstra": {
		"prefix": "atcoder_graph_dijkstra",
		"body": [
		"using Edge = pair<ll, int>;",
		"using Graph = vector<vector<Edge>>;",
		"vector<ll> dijkstra(int st, Graph &g){",
		"    int N = g.size();",
		"    vector<ll> dist(N, LINF);",
		"    dist[st] = 0ll;",
		"    using P = pair<ll, int>;",
		"    priority_queue<P, vector<P>, greater<P>> pq;",
		"    pq.emplace(P{0ll, st});",
		"    while(!pq.empty()){",
		"        ll time = pq.top().first;",
		"        int now = pq.top().second;",
		"        pq.pop();",
		"        if (time > dist[now])continue;",
		"        for(auto e : g[now]){",
		"            ll c = e.first;",
		"            int nxt = e.second;",
		"            if (c + time < dist[nxt]){",
		"                dist[nxt] = c + time;",
		"                pq.push(P{c + time, nxt});",
		"            }",
		"        }",
		"    }",
		"    return dist;",
		"}",
		""
		],
		"description": "dijkstra"
	},
	"bfs": {
		"prefix": "atcoder_graph_bfs",
		"body": [
		"vector<ll> bfs(int st, Graph &g){",
		"    int N = g.size();",
		"    queue<int> que;",
		"    que.push(st);",
		"    vector<ll> dist(N,LINF);",
		"    dist[st] = 0;",
		"    while(!que.empty()){",
		"        auto now = que.front();que.pop();",
		"        for(auto nxt : g[now]){",
		"            if (dist[nxt] != LINF)continue;",
		"            dist[nxt] = dist[now] + 1;",
		"            que.push(nxt);",
		"        }",
		"    }",
		"    return dist;",
		"}",
		""
		],
		"description": "bfs"
	},
	"bellman_ford": {
		"prefix": "atcoder_graph_bellman_ford",
		"body": [
		"// https://yukicoder.me/submissions/968942",
		"using Edge = tuple<ll, int, int>; // (weight, now, nxt)",
		"pair<vector<ll>, vector<ll>> bellman_ford(int V, int st, vector<Edge> &edges){",
		"    vector<ll> dist(V, LINF), negative(V, false); // negative[i] ... iが負閉路に含まれるならtrue",
		"    dist[st] = 0;",
		"    for(int i = 0; i < V - 1; i++){",
		"        bool update = false;",
		"        for(auto &e : edges){",
		"            ll weight;",
		"            int now, nxt;",
		"            tie(weight, now, nxt) = e;",
		"            if(dist[now] != LINF && dist[nxt] > dist[now] + weight){",
		"                dist[nxt] = dist[now] + weight;",
		"                update = true;",
		"            }",
		"        }",
		"        if(!update)return make_pair(dist, negative);",
		"    }",
		"",
		"    for(int i = 0; i < V; i++){",
		"        for(auto &e : edges){",
		"            ll weight;",
		"            int now, nxt;",
		"            tie(weight, now, nxt) = e;",
		"            if(dist[now] != LINF && dist[nxt] > dist[now] + weight){",
		"                dist[nxt] = dist[now] + weight;",
		"                negative[nxt] = true;",
		"            }",
		"            if(negative[now]) negative[nxt] = true;",
		"        }",
		"    }",
		"",
		"    return make_pair(dist, negative);",
		"}",
		""
		],
		"description": "bellman_ford"
	},
	"warshall_floyd": {
		"prefix": "atcoder_graph_warshall_floyd",
		"body": [
		"void warshall_floyd(vector<vector<ll>> &dist){",
		"    int N = dist.size();",
		"    for(int i=0;i<N;i++) dist[i][i] = 0ll;",
		"    for(int k=0;k<N;k++){",
		"        for(int i=0;i<N;i++){",
		"            for(int j=0;j<N;j++){",
		"                chmin(dist[i][j], dist[i][k] + dist[k][j]);",
		"            }",
		"        }",
		"    }",
		"}",
		"// 負閉路はdist[i][i] < 0となるiがあるか",
		"// 経路復元...https://zeosutt.hatenablog.com/entry/2015/05/05/045943",
		"// prev[i][j]...iからjの最短経路でjの一つ前の点",
		"// 初期化:prev[i][j]...i",
		"// 更新:prev[i][j] = prev[k][j]",
		"// 復元:dijkstraと同じように。now = prev[start][now]で更新",
		""
		],
		"description": "warshall_floyd"
	},
	"topological_sort": {
		"prefix": "atcoder_graph_topological_sort",
		"body": [
		"vector<int> topological_sort(Graph &g){",
		"    int N = g.size();",
		"    vector<int> deg(N);",
		"    for(int from_=0;from_<N;from_++){",
		"        for(auto nxt_: g[from_]){",
		"            deg[nxt_]++;",
		"        }",
		"    }",
		"    queue<int> que;",
		"    rep(i,N){",
		"        if (deg[i] == 0) que.push(i);",
		"    }",
		"    vector<int> res;",
		"    while(!que.empty()){",
		"        auto now = que.front(); que.pop();",
		"        res.push_back(now);",
		"        for(auto nxt:g[now]){",
		"            deg[nxt]--;",
		"            if (deg[nxt] == 0){",
		"                que.push(nxt);",
		"            }",
		"        }",
		"    }",
		"    return res;",
		"}",
		""
		],
		"description": "topological_sort"
	},
	//
	// tree algorithm
	//
	"LCT": {
		"prefix": "atcoder_tree_LinkCutTree",
		"body": [
		"",
		"// https://judge.yosupo.jp/submission/206333",
		"//【Link-Cut Tree(可換モノイド)】",
		"/*",
		"* Link_cut_tree<S, op, o>(int n) : O(n)",
		"* 値 o() をもった n 頂点で初期化する.",
		"* 要素は可換モノイド (S, op, o) の元とする.",
		"*",
		"* Link_cut_tree<S, op, o>(vS a) : O(n log n)",
		"* 値 a[0..n) をもった n 頂点で初期化する.",
		"*",
		"* cut(int i) : ならし O(log n)",
		"* 頂点 i とその親との間の辺を切断する.",
		"* 制約:i は根でない.",
		"*",
		"* cut(int s, int t) : ならし O(log n)",
		"* 辺 s-t を切断する(辺がなければ何もしない)",
		"*",
		"* link(int s, int t) : ならし O(log n)",
		"* 頂点 s と根 t に対し,親から子への辺 s→t を繋ぐ.",
		"* 制約:t は根である.",
		"*",
		"* set_root(int rt) : ならし O(log n)",
		"* 頂点 rt を根にする.",
		"*",
		"* S sum(int i) : ならし O(log n)",
		"* 根から頂点 i まで(両端含む)の頂点の値の総和を返す.",
		"*",
		"* set(int i, S x) : ならし O(log n)",
		"* 頂点 i の値を x に変更する.",
		"*",
		"* add(int i, S x) : ならし O(log n)",
		"* 頂点 i の値に x を加える.",
		"*",
		"* bool connectedQ(int s, int t) : ならし O(log n)",
		"* 頂点 s, t が連結かを返す.",
		"*/",
		"template <class S, S(*op)(S, S), S(*o)()>",
		"class Link_cut_tree {",
		"    // 参考 : https://www.slideshare.net/iwiwi/2-12188845",
		"    // 参考 : https://ei1333.github.io/library/structure/lct/link-cut-tree.hpp.html",
		"",
		"    // splay 木(平衡二分探索木)のノード",
		"    // key は Link-Cut 木のノードの深さとし,左ほど浅く右ほど深いものとする.",
		"    struct Node {",
		"        S val; // 頂点の値",
		"        S acc; // 部分木のノードの総和",
		"        bool rev; // 部分木が反転されているか",
		"        Node* p; // 親へのポインタ(heavy path 内部または外部)",
		"        Node* l, * r; // 左右の子へのポインタ",
		"",
		"        Node(S val = o()) : val(val), acc(val), rev(false), p(nullptr), l(nullptr), r(nullptr) {}",
		"",
		"        // 自身が根かを返す.",
		"        bool rootQ() {",
		"            // 親が設定されていなければもちろん根である.",
		"            // そうでなくてもそれが heavy path 外部の親であれば自身は根である.",
		"            return !p || (p->l != this && p->r != this);",
		"        }",
		"",
		"        // 自身の情報を子の情報をもとにして更新する.",
		"        void pushup() {",
		"            acc = op(l ? l->acc : o(), op(val, r ? r->acc : o()));",
		"        }",
		"",
		"        void pushdown() {",
		"            // 反転フラグが立っていたら実際に反転しフラグを折る.",
		"            if (rev) {",
		"                rev = false;",
		"                swap(l, r);",
		"",
		"                // 自分の子については反転フラグを flip しておくだけにする.",
		"                if (l) l->rev = !l->rev;",
		"                if (r) r->rev = !r->rev;",
		"            }",
		"",
		"            // 自身の情報(acc)を子の情報をもとにして更新する.",
		"            pushup();",
		"        }",
		"",
		"        // 右回転する.",
		"        void rotR() {",
		"            Node* my_p = p, * my_pp = my_p->p;",
		"",
		"            // 自分の親と自分の右の子(あれば)を繋ぐ.",
		"            if (my_p->l = r) r->p = my_p;",
		"            my_p->pushup();",
		"",
		"            // 自身と自分の親の親子関係を逆転させる.",
		"            r = my_p; my_p->p = this;",
		"            pushup();",
		"",
		"            // 自身と自分の親の親(あれば)を繋ぐ.",
		"            if (p = my_pp) {",
		"                if (my_pp->l == my_p) my_pp->l = this;",
		"                if (my_pp->r == my_p) my_pp->r = this;",
		"            }",
		"        }",
		"",
		"        // 左回転する.",
		"        void rotL() {",
		"            Node* my_p = p, * my_pp = my_p->p;",
		"",
		"            // 自分の親と自分の左の子(あれば)を繋ぐ.",
		"            if (my_p->r = l) l->p = my_p;",
		"            my_p->pushup();",
		"",
		"            // 自身と自分の親の親子関係を逆転させる.",
		"            l = my_p; my_p->p = this;",
		"            pushup();",
		"",
		"            // 自身と自分の親の親(あれば)を繋ぐ.",
		"            if (p = my_pp) {",
		"                if (my_pp->l == my_p) my_pp->l = this;",
		"                if (my_pp->r == my_p) my_pp->r = this;",
		"            }",
		"        }",
		"",
		"        // 自身を heavy path 内の根に持ってくる(スプレー操作)",
		"        void splay() {",
		"            pushdown();",
		"",
		"            // 自身が根でないかぎり操作を続ける.",
		"            while (!rootQ()) {",
		"                Node* my_p = p;",
		"",
		"                // 自分の親が根である場合",
		"                if (my_p->rootQ()) {",
		"                    my_p->pushdown();",
		"                    pushdown();",
		"",
		"                    // 適切な回転操作を行う.",
		"                    if (my_p->l == this) rotR();",
		"                    else rotL();",
		"                }",
		"                // 自分の親が根でない場合",
		"                else {",
		"                    Node* my_pp = my_p->p;",
		"                    my_pp->pushdown();",
		"                    my_p->pushdown();",
		"                    pushdown();",
		"",
		"                    // 自分の親の親から自分まで同方向に枝が伸びている場合は zig-zig ステップ,",
		"                    // さもなくば zig-zag ステップを実行する.",
		"                    if (my_pp->l == my_p) {",
		"                        // zig-zig ステップ",
		"                        if (my_p->l == this) my_p->rotR(), rotR();",
		"                        // zig-zag ステップ",
		"                        else rotL(), rotR();",
		"                    }",
		"                    else {",
		"                        // zig-zig ステップ",
		"                        if (my_p->r == this) my_p->rotL(), rotL();",
		"                        // zig-zag ステップ",
		"                        else rotR(), rotL();",
		"                    }",
		"                }",
		"            }",
		"        }",
		"    };",
		"",
		"    int n; // 頂点数",
		"    vector<Node> vs; // 頂点のリスト",
		"",
		"    // 木の根から頂点 v までを 1 つの heavy path にし,v を heavy path 内の根とする.",
		"    void expose(Node* v) {",
		"        auto v0(v);",
		"",
		"        // rt : 作成途中の heavy path の根",
		"        Node* rt = nullptr;",
		"",
		"        while (v) {",
		"            // v をいまの heavy path 内の根にもってくる.",
		"            v->splay();",
		"",
		"            // v の右の子を切り離し,作成途中の heavy path を繋ぐ.",
		"            v->r = rt;",
		"            rt = v;",
		"            v->pushup();",
		"",
		"            // 1 つ上の heavy path に移動する.",
		"            v = v->p;",
		"        }",
		"",
		"        // v を構築した heavy path 内の根とする.",
		"        v0->splay();",
		"    }",
		"",
		"    // 頂点 v とその親との間の辺を切断する.",
		"    void cut(Node* v) {",
		"        // 木の根から v までの heavy path を繋ぐ.",
		"        expose(v);",
		"",
		"        // v の親は v より 1 つ浅いので v の左の子孫になっている.",
		"        Node* l = v->l;",
		"",
		"        // v とその親の間の辺を切断する.",
		"        v->l = nullptr;",
		"        l->p = nullptr;",
		"",
		"        v->pushup();",
		"    }",
		"",
		"    // 頂点 v, vp を繋ぎ,v の親を vp とする(v は根であること)",
		"    void link(Node* v, Node* vp) {",
		"        // それぞれの木の根から v, vp までの heavy path を繋ぐ.",
		"        expose(v);",
		"        expose(vp);",
		"",
		"        // vp と v の間の辺を繋ぐ(v の方が深いので v を vp の右の子とする)",
		"        v->p = vp;",
		"        vp->r = v;",
		"",
		"        vp->pushup();",
		"    }",
		"",
		"    // 頂点 v を木の根にする.",
		"    void evert(Node* v) {",
		"        expose(v);",
		"        v->rev = !v->rev;",
		"    }",
		"",
		"public:",
		"    // 値 o() をもった n 頂点で初期化する.",
		"    Link_cut_tree(int n) : n(n), vs(n) { }",
		"",
		"    // 値 a[0..n) をもった n 頂点で初期化する.",
		"    Link_cut_tree(const vector<S>& a) : n((int)a.size()), vs(n) {",
		"        // verify : https://judge.yosupo.jp/problem/dynamic_tree_vertex_add_path_sum",
		"",
		"        rep(i, n) vs[i].val = vs[i].acc = a[i];",
		"    }",
		"",
		"    // 頂点 i とその親との間の辺を切断する.",
		"    void cut(int i) {",
		"        cut(&vs[i]);",
		"    }",
		"",
		"    // 辺 s-t を切断する(なければ何もしない)",
		"    void cut(int s, int t) {",
		"        // verify : https://judge.yosupo.jp/problem/dynamic_tree_vertex_add_path_sum",
		"",
		"        if (s == t) return;",
		"        expose(&vs[s]), expose(&vs[t]);",
		"        if (!vs[s].p) return;",
		"",
		"        if (vs[t].l == &vs[s]) {",
		"            Node* l = vs[t].l;",
		"            vs[t].l = nullptr;",
		"            l->p = nullptr;",
		"            vs[t].pushup();",
		"        }",
		"        else {",
		"            expose(&vs[s]);",
		"            Node* l = vs[s].l;",
		"            vs[s].l = nullptr;",
		"            l->p = nullptr;",
		"            vs[s].pushup();",
		"        }",
		"    }",
		"",
		"    // 頂点 s と根 t に対し,親から子への辺 s→t を繋ぐ.",
		"    void link(int s, int t) {",
		"        // verify : https://judge.yosupo.jp/problem/dynamic_tree_vertex_add_path_sum",
		"",
		"        link(&vs[t], &vs[s]);",
		"    }",
		"",
		"    // 頂点 rt を根にする.",
		"    void set_root(int rt) {",
		"        // verify : https://judge.yosupo.jp/problem/dynamic_tree_vertex_add_path_sum",
		"",
		"        evert(&vs[rt]);",
		"    }",
		"",
		"    // 根から頂点 i まで(両端含む)の頂点の値の総和を返す.",
		"    S sum(int i) {",
		"        // verify : https://judge.yosupo.jp/problem/dynamic_tree_vertex_add_path_sum",
		"",
		"        expose(&vs[i]);",
		"        return vs[i].acc;",
		"    }",
		"",
		"    // 頂点 i の値を x に変更する.",
		"    void set(int i, S x) {",
		"        expose(&vs[i]);",
		"        vs[i].val = x;",
		"        vs[i].pushup();",
		"    }",
		"",
		"    // 頂点 i の値に x を加える.",
		"    void add(int i, S x) {",
		"        // verify : https://judge.yosupo.jp/problem/dynamic_tree_vertex_add_path_sum",
		"",
		"        expose(&vs[i]);",
		"        vs[i].val = op(x, vs[i].val);",
		"        vs[i].pushup();",
		"    }",
		"",
		"    // 頂点 s, t が連結かを返す.",
		"    bool connectedQ(int s, int t) {",
		"        // verify : https://atcoder.jp/contests/abc350/tasks/abc350_g",
		"",
		"        if (s == t) return true;",
		"        expose(&vs[s]), expose(&vs[t]);",
		"        return vs[s].p;",
		"    }",
		"",
		"#ifdef _MSC_VER",
		"    friend ostream& operator<<(ostream& os, Link_cut_tree LCT) {",
		"        rep(i, LCT.n) {",
		"            LCT.set_root(i);",
		"            os << LCT.sum(i) << \" \";",
		"        }",
		"        return os;",
		"    }",
		"#endif",
		"};"
		],
		"description": "LCT"
	},
	"LCA": {
		"prefix": "atcoder_tree_LCA",
		"body": [
		"//https://algo-logic.info/lca/",
		"struct LCA{",
		"    vector<vector<int>> doubling; //doubling[k][u]...頂点uからpow(2,k)遡った頂点番号",
		"    vector<int> dist; //dist[u]...頂点uからrootまでの距離",
		"    LCA(const Graph &G , int root = 0){ init(G,root) ;}",
		"    ",
		"    void init(const Graph &G , int root = 0){",
		"        int N = G.size();",
		"        int logN = 1;",
		"        while((1<<logN) <= N) logN++;",
		"        doubling.assign(logN,vector<int>(N,-1));",
		"        dist.assign(N,-1);;",
		"        dfs(G,root,-1,0);",
		"        for (int k=0;k<logN-1;k++){",
		"            for (int now=0;now<N;now++){",
		"                if (doubling[k][now] < 0) doubling[k+1][now] = -1;",
		"                else doubling[k+1][now] = doubling[k][doubling[k][now]];",
		"            }",
		"        }",
		"    }",
		"    void dfs(const Graph &G, int now, int par , int depth){",
		"        doubling[0][now] = par;",
		"        dist[now] = depth;",
		"        for(auto nxt : G[now]){",
		"            if (nxt == par) continue;",
		"            dfs(G,nxt,now,depth+1);",
		"        }",
		"    }",
		"    int query(int u, int v){// 頂点uと頂点vのLCA",
		"        if (dist[u] < dist[v]) swap(u,v);",
		"        int logN = doubling.size();",
		"        //LCAまでの距離を同じにする、O(logN)",
		"        for (int k=0;k<logN;k++){",
		"            if ((dist[u] - dist[v]) >> k & 1){",
		"                u = doubling[k][u];",
		"            }",
		"        }",
		"        if (u == v) return u;",
		"        for (int k=logN-1;k>=0;k--){",
		"            if (doubling[k][u] != doubling[k][v]){",
		"                u = doubling[k][u];",
		"                v = doubling[k][v];",
		"            }",
		"        }",
		"        return doubling[0][u];",
		"    }",
		"    int get_dist(int u,int v){",
		"        return dist[u] + dist[v] - 2 * dist[query(u,v)];",
		"    }",
		"    bool is_on_path(int u,int v, int target){",
		"        return get_dist(u,v) == get_dist(u,target) + get_dist(target,v);",
		"    }",
		"};"
		],
		"description": "LCA"
	},
	"HLD": {
	"prefix": "atcoder_tree_hld",
	"body": [
		"// HL-Decomposition",
		"// vid: id of v after HL-Decomposition",
		"// inv: inv[vid[v]] = v",
		"// par: id of parent",
		"// depth",
		"// subsize: size of subtree",
		"// head: head-id in the heavy-path",
		"// prev, next: prev-id, next-id in the heavy-path",
		"// type: the id of tree for forest",
		"// vend: the last-id of node in v-subtree",
		"typedef vector<vector<int> > Graph;",
		"struct HLDecomposition {",
		"    int n;",
		"    Graph G;",
		"    vector<int> vid, inv, par, depth, subsize, head, prev, next, type;",
		"    ",
		"    // construct",
		"    HLDecomposition() { }",
		"    HLDecomposition(const Graph &G_) :",
		"        n((int)G_.size()), G(G_),",
		"        vid(n, -1), inv(n), par(n), depth(n), subsize(n, 1),",
		"        head(n), prev(n, -1), next(n, -1), type(n) { }",
		"    void build(vector<int> roots = {0}) {",
		"        int curtype = 0, pos = 0;",
		"        for (auto r : roots) decide_heavy_edge(r), reconstruct(r, curtype++, pos);",
		"    }",
		"    void decide_heavy_edge(int r) {",
		"        stack<pair<int,int> > st;",
		"        par[r] = -1, depth[r] = 0;",
		"        st.emplace(r, 0);",
		"        while (!st.empty()) {",
		"            int v = st.top().first;",
		"            int &i = st.top().second;",
		"            if (i < (int)G[v].size()) {",
		"                int e = G[v][i++];",
		"                if (e == par[v]) continue;",
		"                par[e] = v, depth[e] = depth[v] + 1;",
		"                st.emplace(e, 0);",
		"            }",
		"            else {",
		"                st.pop();",
		"                int maxsize = 0;",
		"                for (auto e : G[v]) {",
		"                    if (e == par[v]) continue;",
		"                    subsize[v] += subsize[e];",
		"                    if (maxsize < subsize[e]) maxsize = subsize[e], prev[e] = v, next[v] = e;",
		"                }",
		"            }",
		"        }",
		"    }",
		"    void reconstruct(int r, int curtype, int &pos) {",
		"        stack<int> st({r});",
		"        while (!st.empty()) {",
		"            int start = st.top(); st.pop();",
		"            for (int v = start; v != -1; v = next[v]) {",
		"                type[v] = curtype;",
		"                vid[v] = pos++;",
		"                inv[vid[v]] = v;",
		"                head[v] = start;",
		"                for (auto e : G[v]) if (e != par[v] && e != next[v]) st.push(e);",
		"            }",
		"        }",
		"    }",
		"    ",
		"    // node query [u, v], f([left, right])",
		"    void foreach_nodes(int u, int v, const function<void(int,int)> &f) {",
		"        while (true) {",
		"            if (vid[u] > vid[v]) swap(u, v);",
		"            f(max(vid[head[v]], vid[u]), vid[v]);",
		"            if (head[u] != head[v]) v = par[head[v]];",
		"            else break;",
		"        }",
		"    }",
		"    ",
		"    // edge query [u, v], f([left, right])",
		"    void foreach_edges(int u, int v, const function<void(int,int)> &f) {",
		"        while (true) {",
		"            if (vid[u] > vid[v]) swap(u, v);",
		"            if (head[u] != head[v]) {",
		"                f(vid[head[v]], vid[v]);",
		"                v = par[head[v]];",
		"            }",
		"            else {",
		"                if (u != v) {",
		"                    f(vid[u]+1, vid[v]);",
		"                }",
		"                break;",
		"            }",
		"        }",
		"    }",
		"",
		"    // https://atcoder.jp/contests/abc138/submissions/38833623",
		"    void subtree_nodes(int v, const function<void(int,int)> &f) {",
		"        f(vid[v],vid[v]+subsize[v]);",
		"    }",
		"",
		"    // https://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=7464630#1",
		"    void subtree_edges(int v, const function<void(int,int)> &f) {",
		"        f(vid[v] + 1, vid[v] + subsize[v]);",
		"    }",
		"",
		"    // LCA",
		"    int lca(int u, int v) {",
		"        while (true) {",
		"            if (vid[u] > vid[v]) swap(u, v);",
		"            if (head[u] == head[v]) return u;",
		"            v = par[head[v]];",
		"        }",
		"    }",
		"};",
		"// https://drken1215.hatenablog.com/entry/2018/08/14/193500",
		"// HLDecomposition hld(g);",
		"// hld.build();", 
		"//",
		"// [path_query]",
		"// hld.foreach_nodes(v, u, [&](int l, int r) {seg.apply(l,r+1,x);});",
		"// hld.foreach_edges(v, u, [&](int l, int r) {ans += seg.prod(l,r+1,x);}); // range sum",
		"// hld.foreach_edges(v, u, [&](int l, int r) {ans = max(ans, seg.prod(l,r+1,x));}); // range max",
		"//",
		"// [subtree_query]",
		"// hld.subtree_nodes(v,[&](int l, int r) {seg.apply(l,r,x);});",
		"// hld.subtree_edges(v,[&](int l, int r) {seg.apply(l,r,x);});",
		"// ",
		"// 頂点iに対応するid -> hld.vid[i]",
		"// ex) 頂点iの値を変更 -> seg.set(hld.vid[i], A[i])"
	],
	"description": "HLD"
	},
	"rerooting": {
		"prefix": "atcoder_tree_rerooting",
		"body": [
		"template<class E, class V, E (*merge)(E, E), E (*e)(), E (*put_edge)(V, int), V (*put_vertex)(E, int)>",
		"struct RerootingDP {",
		"    struct edge{",
		"        int from, to, idx, rev_idx;",
		"    };",
		"    RerootingDP (int _n = 0) : n(_n) { es.resize(n);}",
		"    void add_edge(int u, int v, int idx1, int idx2){",
		"        es[u].push_back({u,v,idx1,idx2});",
		"        es[v].push_back({v,u,idx2,idx1});",
		"    }",
		"    V build(int v = 0){",
		"        root = v;",
		"        vis.resize(n,0);",
		"        outs.resize(n);",
		"        return dfs(root);",
		"    }",
		"    vector<V> reroot(){",
		"        reverse_edge.resize(n);",
		"        reverse_edge[root] = e();",
		"        answers.resize(n);",
		"        bfs(root);",
		"        return answers;",
		"    }",
		"  private:",
		"    int n, root;",
		"    vector<vector<edge>> es;",
		"    vector<int> vis;",
		"    vector<vector<E>> outs;",
		"    vector<E> reverse_edge;",
		"    vector<V> answers;",
		"    V dfs(int v){",
		"        vis[v]++;",
		"        E val = e();",
		"        for (auto &p : es[v]){",
		"            if (vis[p.to] > 0 && p.to != es[v].back().to) swap(p,es[v].back());",
		"            if (vis[p.to] > 0) continue;",
		"            E nval = put_edge(dfs(p.to),p.idx);",
		"            outs[v].emplace_back(nval);",
		"            val = merge(val,nval);",
		"        }",
		"        return put_vertex(val,v);",
		"    }",
		"    void bfs(int v){",
		"        int siz = outs[v].size();",
		"        vector<E> lui(siz+1), rui(siz+1);",
		"        lui[0] = e(), rui[siz] = e();",
		"        for (int i = 0; i < siz; i++) lui[i+1] = merge(lui[i],outs[v][i]);",
		"        for (int i = siz-1; i >= 0; i--) rui[i] = merge(outs[v][i],rui[i+1]);",
		"        for (int i = 0; i < siz; i++){",
		"            reverse_edge[es[v][i].to] = put_edge(put_vertex(merge(merge(lui[i],rui[i+1]),reverse_edge[v]),v),es[v][i].rev_idx);",
		"            bfs(es[v][i].to);",
		"        }",
		"        answers[v] = put_vertex(merge(lui[siz],reverse_edge[v]), v);",
		"    }",
		"};",
		"",
		"// Education dp subtree",
		"// https://atcoder.jp/contests/dp/submissions/37662999",
		"using T_monoid = mint; // E",
		"using T_DP = mint; // V",
		"",
		"T_monoid merge(T_monoid a, T_monoid b){",
		"    return a * b;",
		"}",
		"T_monoid e(){",
		"    return mint(1);",
		"}",
		"T_monoid put_edge(T_DP x, int i){",
		"    return x + 1;",
		"}",
		"T_DP put_vertex(T_monoid x, int v){",
		"    return x;",
		"}",
		"// 参考",
		"// https://trap.jp/post/1702/",
		"",
		"// https://null-mn.hatenablog.com/entry/2020/04/14/124151 ",
		"// fがput_edge, gがput_vertex",
		"// 辺の情報が必要なときはedge[i]を作る、また頂点の情報が必要な時はvertex[v]を作る",
		""
		],
		"description": "rerooting"
	},
	//
	// string algorithm
	//
	"toint": {
		"prefix": "atcoder_string_toint",
		"body": [
		"struct string_converter {",
		"    char start = 0;",
		"    char type(const char &c) const { return (islower(c) ? 'a' : isupper(c) ? 'A' : isdigit(c) ? '0' : 0); }",
		"    int convert(const char &c) {",
		"        if(!start) start = type(c);",
		"        return c - start;",
		"    }",
		"    int convert(const char &c, const string &chars) { return chars.find(c); }",
		"    template <typename T> auto convert(const T &v) {",
		"        vector<decltype(convert(v[0]))> ret;",
		"        ret.reserve(v.size());",
		"        for(auto &&e : v) ret.emplace_back(convert(e));",
		"        return ret;",
		"    }",
		"    template <typename T> auto convert(const T &v, const string &chars) {",
		"        vector<decltype(convert(v[0], chars))> ret;",
		"        ret.reserve(v.size());",
		"        for(auto &&e : v) ret.emplace_back(convert(e, chars));",
		"        return ret;",
		"    }",
		"    int operator()(const char &v, char s = 0) {",
		"        start = s;",
		"        return convert(v);",
		"    }",
		"    int operator()(const char &v, const string &chars) { return convert(v, chars); }",
		"    template <typename T> auto operator()(const T &v, char s = 0) {",
		"        start = s;",
		"        return convert(v);",
		"    }",
		"    template <typename T> auto operator()(const T &v, const string &chars) { return convert(v, chars); }",
		"} toint;",
		"https://twitter.com/noimi_kyopro/status/1613160018769252361",
		"// cout << toint('1') << endl; // 1",
		"// cout << toint('a') << endl; // 0",
		"// cout << toint('A') << endl; // 0",
		"// cout << toint('B') << endl; // 1",
		"// string MOJI = \"ABC123abc\";",
		"// for(auto x:MOJI) cout << toint(x) << endl; // 0 1 2 1 2 3 0 1 2",
		"// vector<int> c = toint(MOJI);",
		"// for(auto x:c) cout << x << endl; // 0 1 2 -16 -15 -14 32 33 34",
		"// cout << toint('#',\"#.\") << endl; // 0",
		"// cout << toint('.',\"#.\") << endl; // 1",
		""
		],
		"description": "toint"
	},
	"rolling_hash": {
		"prefix": "atcoder_string_rollinghash",
		"body": [
		"struct RollingHash{",
		"    static const int B = 3;",
		"    long long base[B] = {114514, 1919, 810};",
		"    long long mod[B] = {1000000007, 1000000009, 998244353};",
		"",
		"    int N;",
		"    vector<vector<long long>> hash;",
		"    vector<vector<long long>> pw;",
		"    RollingHash(string &S){",
		"        N = S.size();",
		"        hash.resize(B);",
		"        pw.resize(B);",
		"        for(int b = 0; b < B; b++){",
		"            hash[b].resize(N + 1, 0);",
		"            pw[b].resize(N + 1, 1);",
		"",
		"            for(int i = 0; i < N; i++){",
		"                hash[b][i + 1] = (hash[b][i] * base[b] + S[i]) % mod[b];",
		"                pw[b][i + 1] = pw[b][i] * base[b] % mod[b];",
		"            }",
		"        }",
		"    }",
		"",
		"    vector<long long> get(int l, int r){",
		"        vector<long long> res(B);",
		"        for(int b = 0; b < B; b++){",
		"            res[b] = (hash[b][r] - (hash[b][l] * pw[b][r - l]) % mod[b] + mod[b]) % mod[b];",
		"        }",
		"        return res;",
		"    }",
		"",
		"    int LCP(int l1, int r1, int l2, int r2){",
		"        // O(log|S|)",
		"        // return LCP between S[l1, r1) and S[l2, r2)",
		"        int len = min(r1 - l1, r2 - l2);",
		"        int ok = -1, ng = len + 1;",
		"        while(abs(ok - ng) > 1){",
		"            int mid = (ok + ng) / 2;",
		"            if (get(l1, l1 + mid) == get(l2, l2 + mid)) ok = mid;",
		"            else ng = mid;",
		"        }",
		"        return ok;",
		"    }",
		"};",
		""
		],
		"description": "rolling_hash"
	},
	"Trie": {
		"prefix": "atcoder_string_trie",
		"body": [
		"//https://algo-logic.info/trie-tree/",
		"/* Trie 木: 文字の種類(char_size)、int型で0に対応する文字(base)",
		"    insert(word): 単語 word を Trie 木に挿入する",
		"    search(word): 単語 word が Trie 木にあるか判定する",
		"    start_with(prefix):  prefix が一致する単語が Trie 木にあるか判定する",
		"    count(): 挿入した単語の数を返す",
		"    size(): Trie 木の頂点数を返す",
		"    計算量:insert, search ともに O(M)(Mは単語の長さ)",
		"*/",
		"template <int char_size, int base>",
		"struct Trie {",
		"    struct Node {            // 頂点を表す構造体",
		"        vector<int> next;    // 子の頂点番号を格納。存在しなければ-1",
		"        vector<int> accept;  // 末端がこの頂点になる単語の word_id を保存",
		"        int c;               // base からの間隔をint型で表現したもの",
		"        int common;          // いくつの単語がこの頂点を共有しているか",
		"        Node(int c_) : c(c_), common(0) {",
		"            next.assign(char_size, -1);",
		"        }",
		"    };",
		"",
		"    vector<Node> nodes;  // trie 木本体",
		"    int root;",
		"    Trie() : root(0) {",
		"        nodes.push_back(Node(root));",
		"    }",
		"",
		"    // 単語の挿入",
		"    void insert(const string &word, int word_id) {",
		"        int node_id = 0;",
		"        for (int i = 0; i < (int)word.size(); i++) {",
		"            int c = (int)(word[i] - base);",
		"            int &next_id = nodes[node_id].next[c];",
		"            if (next_id == -1) {  // 次の頂点が存在しなければ追加",
		"                next_id = (int)nodes.size();",
		"                nodes.push_back(Node(c));",
		"            }",
		"            ++nodes[node_id].common;",
		"            node_id = next_id;",
		"        }",
		"        ++nodes[node_id].common;",
		"        nodes[node_id].accept.push_back(word_id);",
		"    }",
		"    void insert(const string &word) {",
		"        insert(word, nodes[0].common);",
		"    }",
		"",
		"    // 単語とprefixの検索",
		"    bool search(const string &word, bool prefix = false) {",
		"        int node_id = 0;",
		"        for (int i = 0; i < (int)word.size(); i++) {",
		"            int c = (int)(word[i] - base);",
		"            int &next_id = nodes[node_id].next[c];",
		"            if (next_id == -1) {  // 次の頂点が存在しなければ終了",
		"                return false;",
		"            }",
		"            node_id = next_id;",
		"        }",
		"        return (prefix) ? true : nodes[node_id].accept.size() > 0;",
		"    }",
		"",
		"    // prefix を持つ単語が存在するかの検索",
		"    bool start_with(const string &prefix) {",
		"        return search(prefix, true);",
		"    }",
		"",
		"    // 挿入した単語の数",
		"    int count() const {",
		"        return (nodes[0].common);",
		"    }",
		"    // Trie木のノード数 , ただしrootも含む",
		"    int size() const {",
		"        return ((int)nodes.size());",
		"    }",
		"    ",
		"    // node_id = tmpの下に文字c(c = 0,1,..25)で終わる文字があるか",
		"    bool match(int tmp, int c){",
		"        int nxt_id = nodes[tmp].next[c];",
		"        return (nxt_id != -1) && (nodes[nxt_id].accept.size() > 0);",
		"    }",
		"};",
		"//Trie<26,'a'> trie;",
		"",
		""
		],
		"description": "Trie"
	},
	// 
	// AHC
	// 
	"ahc_main": {
		"prefix": "atcoder_ahc_main",
		"body": [
			"#include <bits/stdc++.h>",
			"#include <atcoder/all>",
			"using namespace std;",
			"using namespace atcoder;",
			"istream &operator>>(istream &is, modint &a) { long long v; is >> v; a = v; return is; }",
			"ostream &operator<<(ostream &os, const modint &a) { return os << a.val(); }",
			"istream &operator>>(istream &is, modint998244353 &a) { long long v; is >> v; a = v; return is; }",
			"ostream &operator<<(ostream &os, const modint998244353 &a) { return os << a.val(); }",
			"istream &operator>>(istream &is, modint1000000007 &a) { long long v; is >> v; a = v; return is; }",
			"ostream &operator<<(ostream &os, const modint1000000007 &a) { return os << a.val(); }",
			"",
			"typedef long long ll;",
			"typedef pair<int, int> pii;",
			"typedef pair<ll, ll> pll;",
			"#define FOR(i,l,r) for (int i = l;i < (int)(r); i++)",
			"#define rep(i,n) for (int i = 0;i < (int)(n); i++)",
			"#define all(x) x.begin(), x.end()",
			"template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }",
			"template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }",
			"",
			"#ifdef LOCAL",
			"    #include <debug_print.hpp>",
			"    #define debug(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__)",
			"#else",
			"    #define debug(...) (static_cast<void>(0))",
			"#endif",
			"",
			"// https://github.com/thun-c/thunder_library/blob/main/thunder/lib/timer.cpp",
			"/// 軽量な実行時間計測器。",
			"/// `reset()` で計測開始を更新し、`elapsed()` で経過秒(float)を返す。",
			"struct Timer {",
			"    chrono::steady_clock::time_point t_begin;",
			"",
			"    Timer() { reset(); }",
			"",
			"    /// 計測開始時刻を現在時刻に戻す。",
			"    void reset() { t_begin = chrono::steady_clock::now(); }",
			"",
			"    /// 計測開始からの経過時間を秒で返す。",
			"    float elapsed() const {",
			"        return chrono::duration<float>(chrono::steady_clock::now() - t_begin).count();",
			"    }",
			"} timer;",
			"",
			"// https://atcoder.jp/contests/ahc063/submissions/74942932",
			"struct RNG {",
			"    uint64_t s[2];",
			"    RNG(uint64_t seed) { reset(seed); }",
			"    RNG() { reset(time(0)); }",
			"    using result_type = uint32_t;",
			"    static constexpr uint32_t min() { return numeric_limits<uint32_t>::min(); }",
			"    static constexpr uint32_t max() { return numeric_limits<uint32_t>::max(); }",
			"    uint32_t operator()() { return randomInt32(); }",
			"    static inline uint64_t rotl(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); }",
			"    inline void reset(uint64_t seed) {",
			"        struct splitmix64_state {",
			"            uint64_t s;",
			"            uint64_t splitmix64() {",
			"                uint64_t result = (s += 0x9E3779B97f4A7C15);",
			"                result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9;",
			"                result = (result ^ (result >> 27)) * 0x94D049BB133111EB;",
			"                return result ^ (result >> 31);",
			"            }",
			"        };",
			"        splitmix64_state sm{seed};",
			"        s[0] = sm.splitmix64();",
			"        s[1] = sm.splitmix64();",
			"    }",
			"    uint64_t next() {",
			"        const uint64_t s0 = s[0];",
			"        uint64_t s1 = s[1];",
			"        const uint64_t result = rotl(s0 * 5, 7) * 9;",
			"        s1 ^= s0;",
			"        s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16);",
			"        s[1] = rotl(s1, 37);",
			"        return result;",
			"    }",
			"    inline uint32_t randomInt32() { return next(); }",
			"    inline uint64_t randomInt64() { return next(); }",
			"    inline uint32_t random32(uint32_t r) { return (((uint64_t)randomInt32()) * r) >> 32; }",
			"    inline uint64_t random64(uint64_t r) { return randomInt64() % r; }",
			"    inline uint32_t randomRange32(uint32_t l, uint32_t r) { return l + random32(r - l + 1); }",
			"    inline uint64_t randomRange64(uint64_t l, uint64_t r) { return l + random64(r - l + 1); }",
			"    inline double randomDouble() { return (double)randomInt32() / 4294967296.0; }",
			"    inline double randomDoubleOpen01() { return (randomInt32() + 1.0) / 4294967297.0; }",
			"    inline float randomFloat() { return (float)randomInt32() / 4294967296.0; }",
			"    inline double randomRangeDouble(double l, double r) { return l + randomDouble() * (r - l); }",
			"    inline double randomGaussian(double mean = 0.0, double stddev = 1.0) {",
			"        double u1 = randomDoubleOpen01();",
			"        double u2 = randomDouble();",
			"        double z = sqrt(-2.0 * log(u1)) * cos(2.0 * 3.141592653589793238 * u2);",
			"        return mean + stddev * z;",
			"    }",
			"    template <class T> void shuffle(vector<T>& v) {",
			"        int sz = v.size();",
			"        for (int i = sz; i > 1; i--) swap(v[i - 1], v[random32(i)]);",
			"    }",
			"    template <class T> void shuffle(T* fr, T* to) {",
			"        int sz = distance(fr, to);",
			"        for (int i = sz; i > 1; i--) swap(fr[i - 1], fr[random32(i)]);",
			"    }",
			"    template <class T> inline int sample_index(vector<T> const& v) { return random32(v.size()); }",
			"    template <class T> inline T sample(vector<T> const& v) { return v[sample_index(v)]; }",
			"} rng(42);",
			"",
			"struct Input {",
			"    void input() {",
			"    }",
			"};",
			"",
			"struct Solver {",
			"    const Input& input;",
			"",
			"    explicit Solver(const Input& input) : input(input) {}",
			"",
			"    void solve() {",
			"        timer.reset();",
			"    }",
			"",
			"    void print() const {",
			"    }",
			"};",
			"",
			"int main() {",
			"    ios::sync_with_stdio(false);",
			"    cin.tie(nullptr);",
			"",
			"    Input input;",
			"    input.input();",
			"",
			"    Solver solver(input);",
			"    solver.solve();",
			"    solver.print();",
			"    return 0;",
			"}",
			""
		],
		"description": "ahc_main"
	},
	"fastset": {
		"prefix": "atcoder_ahc_fastset",
		"body": [
			"// 整数集合 [0, n) に対する insert/erase/next/prev が O(log n / log 64) の 64 分木。",
			"// std::set<int> より高速。",
			"//",
			"// Usage:",
			"//   FastSet fs(N);",
			"//   fs.insert(i);",
			"//   fs.erase(i);",
			"//   fs.contains(i);          // O(1)",
			"//   fs.next(i);              // i 以上の最小値。なければ N。",
			"//   fs.prev(i);              // i 以下の最大値。なければ -1。",
			"//   fs.min_val();            // 最小値",
			"//   fs.max_val();            // 最大値",
			"//   fs.empty();",
			"struct FastSet {",
			"    static constexpr int B = 64;",
			"    int n_, log_;",
			"    vector<vector<uint64_t>> d_;",
			"",
			"    FastSet() : n_(0), log_(0) {}",
			"    explicit FastSet(int n) : n_(n), log_(0) {",
			"        if (n == 0) return;",
			"        int m = n;",
			"        do {",
			"            d_.push_back(vector<uint64_t>((m + B - 1) / B, 0));",
			"            m = (m + B - 1) / B;",
			"        } while (m > 1);",
			"        log_ = (int)d_.size();",
			"    }",
			"",
			"    void insert(int i) {",
			"        for (int h = 0; h < log_; h++) {",
			"            d_[h][i / B] |= 1ULL << (i % B);",
			"            i /= B;",
			"        }",
			"    }",
			"",
			"    void erase(int i) {",
			"        for (int h = 0; h < log_; h++) {",
			"            d_[h][i / B] &= ~(1ULL << (i % B));",
			"            if (d_[h][i / B]) break;",
			"            i /= B;",
			"        }",
			"    }",
			"",
			"    bool contains(int i) const { return (d_[0][i / B] >> (i % B)) & 1; }",
			"    bool empty() const { return d_[log_ - 1][0] == 0; }",
			"",
			"    // i 以上の最小値。なければ n_ を返す。",
			"    int next(int i) const {",
			"        for (int h = 0; h < log_; h++) {",
			"            int b = i / B;",
			"            if (b >= (int)d_[h].size()) break;",
			"            uint64_t f = d_[h][b] >> (i % B);",
			"            if (!f) { i = b + 1; continue; }",
			"            i += __builtin_ctzll(f);",
			"            for (int g = h - 1; g >= 0; g--)",
			"                i = i * B + __builtin_ctzll(d_[g][i]);",
			"            return i;",
			"        }",
			"        return n_;",
			"    }",
			"",
			"    // i 以下の最大値。なければ -1 を返す。",
			"    int prev(int i) const {",
			"        for (int h = 0; h < log_; h++) {",
			"            if (i < 0) break;",
			"            int b = i / B;",
			"            uint64_t f = d_[h][b] << (B - 1 - i % B);",
			"            if (!f) { i = b - 1; continue; }",
			"            i -= __builtin_clzll(f);",
			"            for (int g = h - 1; g >= 0; g--)",
			"                i = i * B + 63 - __builtin_clzll(d_[g][i]);",
			"            return i;",
			"        }",
			"        return -1;",
			"    }",
			"",
			"    int min_val() const { return next(0); }",
			"    int max_val() const { return prev(n_ - 1); }",
			"};"
			],
		"description": "fastset"
	},
	"hashmap": {
		"prefix": "atcoder_ahc_hashmap",
		"body": [
			"// open addressing, linear probing。unordered_map より高速。",
			"// Key にはハッシュ適用済みの値を渡す。n は格納要素数の 16 倍程度。",
			"// clear() は O(1)(stamp インクリメントのみ)。",
			"//",
			"// Usage:",
			"//   HashMap<uint64_t, int> seen(beam_width * 16);",
			"//   auto [exists, idx] = seen.get_index(hash);",
			"//   if (!exists) seen.set(idx, hash, node_id);",
			"//   int v = seen.get(idx);",
			"//   seen.clear();  // 次ターンへ O(1)",
			"template<class Key, class T>",
			"struct HashMap {",
			"    uint32_t n_;",
			"    uint32_t current_stamp_ = 1;",
			"    vector<uint32_t> stamp_;",
			"    vector<pair<Key, T>> data_;",
			"",
			"    explicit HashMap(uint32_t n) {",
			"        if (n % 2 == 0) ++n;",
			"        n_ = n;",
			"        stamp_.assign(n_, 0);",
			"        data_.resize(n_);",
			"    }",
			"",
			"    // {存在するか, index} を返す。set/get には index を使う。",
			"    pair<bool, int> get_index(Key key) const {",
			"        uint32_t i = (uint32_t)(key % n_);",
			"        while (stamp_[i] == current_stamp_) {",
			"            if (data_[i].first == key) return {true, (int)i};",
			"            if (++i == n_) i = 0;",
			"        }",
			"        return {false, (int)i};",
			"    }",
			"",
			"    void set(int i, Key key, T value) {",
			"        stamp_[i] = current_stamp_;",
			"        data_[i] = {key, value};",
			"    }",
			"",
			"    T get(int i) const { return data_[i].second; }",
			"",
			"    void clear() {",
			"        if (++current_stamp_ == 0) {",
			"            fill(stamp_.begin(), stamp_.end(), 0);",
			"            current_stamp_ = 1;",
			"        }",
			"    }",
			"};"
		],
		"description": "hashmap"
	},
	"conntable": {
		"prefix": "atcoder_ahc_conntable",
		"body": [
			"// 3x3 局所連結性テーブル。8近傍ビットマスク(256通り)の連結成分数を事前計算。",
			"// conn8=true で8連結(斜め隣接あり)、false で4連結(上下左右のみ)。",
			"//",
			"// 近傍ビット配置:",
			"//   0 1 2",
			"//   3 C 4",
			"//   5 6 7",
			"//",
			"// Usage:",
			"//   ConnTable<>      ct;   // 8連結(デフォルト)",
			"//   ConnTable<false> ct;   // 4連結",
			"//   uint8_t mask = ct.neighbors(grid, r, c, H, W);  // grid[r][c] が 0/1 の2次元配列",
			"//   int  comp = ct.components(mask);                 // 中心セルを除いた連結成分数",
			"//   bool safe = ct.can_remove(mask);                  // 削除しても連結性が保たれるか",
			"//",
			"//   // 典型: セル(r,c)を安全に削除できるか確認して消す",
			"//   if (ct.can_remove(ct.neighbors(grid, r, c, H, W))) grid[r][c] = 0;",
			"template<bool conn8 = true>",
			"struct ConnTable {",
			"    uint8_t table[256];",
			"",
			"    ConnTable() {",
			"        for (int mask = 0; mask < 256; mask++)",
			"            table[mask] = count_components(mask);",
			"    }",
			"",
			"    int  components(uint8_t mask) const { return table[mask]; }",
			"    bool can_remove(uint8_t mask) const { return table[mask] <= 1; }",
			"",
			"    template<class Grid>",
			"    uint8_t neighbors(const Grid& grid, int r, int c, int H, int W) const {",
			"        static const int dr[] = {-1,-1,-1, 0, 0, 1, 1, 1};",
			"        static const int dc[] = {-1, 0, 1,-1, 1,-1, 0, 1};",
			"        uint8_t mask = 0;",
			"        for (int k = 0; k < 8; k++) {",
			"            int nr = r + dr[k], nc = c + dc[k];",
			"            if (nr >= 0 && nr < H && nc >= 0 && nc < W && grid[nr][nc])",
			"                mask |= 1 << k;",
			"        }",
			"        return mask;",
			"    }",
			"",
			"private:",
			"    static int count_components(int mask) {",
			"        static const int adj8[8][4] = {",
			"            {1, 3, -1, -1},   // 0",
			"            {0, 2,  3,  4},   // 1",
			"            {1, 4, -1, -1},   // 2",
			"            {0, 1,  5,  6},   // 3",
			"            {1, 2,  6,  7},   // 4",
			"            {3, 6, -1, -1},   // 5",
			"            {3, 4,  5,  7},   // 6",
			"            {4, 6, -1, -1},   // 7",
			"        };",
			"        static const int adj4[8][4] = {",
			"            {1, 3, -1, -1},   // 0",
			"            {0, 2, -1, -1},   // 1",
			"            {1, 4, -1, -1},   // 2",
			"            {0, 5, -1, -1},   // 3",
			"            {2, 7, -1, -1},   // 4",
			"            {3, 6, -1, -1},   // 5",
			"            {5, 7, -1, -1},   // 6",
			"            {4, 6, -1, -1},   // 7",
			"        };",
			"        const auto& adj = conn8 ? adj8 : adj4;",
			"        int comp = 0;",
			"        uint8_t visited = 0;",
			"        for (int i = 0; i < 8; i++) {",
			"            if (!((mask >> i) & 1) || (visited >> i) & 1) continue;",
			"            comp++;",
			"            uint8_t stk = 1 << i;",
			"            visited |= 1 << i;",
			"            while (stk) {",
			"                int u = __builtin_ctz(stk);",
			"                stk &= stk - 1;",
			"                for (int k = 0; k < 4 && adj[u][k] != -1; k++) {",
			"                    int v = adj[u][k];",
			"                    if (((mask >> v) & 1) && !((visited >> v) & 1)) {",
			"                        visited |= 1 << v;",
			"                        stk |= 1 << v;",
			"                    }",
			"                }",
			"            }",
			"        }",
			"        return comp;",
			"    }",
			"};",
			"ConnTable<> conn_table;   // 8連結。4連結が必要なら ConnTable<false> を別途宣言。",
			""
		],
		"description": "conntable"
	},
	"dial": {
		"prefix": "atcoder_ahc_dial",
		"body": [
			"// Dial's アルゴリズム(バケットキュー)。辺コストが小さい整数のとき priority_queue より高速。",
			"// 時間計算量: O(V + E + max_dist)、空間計算量: O(V + E + max_cost)",
			"// max_cost = 最大辺コスト(BFS なら 1)",
			"// max_dist = 探索する最大距離(省略時は全到達頂点を探索)",
			"//",
			"// Usage:",
			"//   vector<vector<pair<int,int>>> adj(N);  // adj[v] = {{neighbor, weight}, ...}",
			"//   auto dist = dial(start, N, adj, 1);              // BFS: 全頂点",
			"//   auto dist = dial(start, N, adj, max_cost);       // 全頂点",
			"//   auto dist = dial(start, N, adj, max_cost, max_dist);  // 距離 max_dist 以内",
			"vector<int> dial(int start, int n,",
			"                 const vector<vector<pair<int,int>>>& adj, int max_cost, int max_dist = -1) {",
			"    const int D = max_cost + 1;",
			"    vector<int> dist(n, INT_MAX);",
			"    vector<vector<int>> bucket(D);",
			"    dist[start] = 0;",
			"    bucket[0].push_back(start);",
			"    int pending = 1;",
			"    for (int d = 0; pending > 0; d++) {",
			"        int bi = d % D;",
			"        pending -= (int)bucket[bi].size();",
			"        for (int v : bucket[bi]) {",
			"            if (dist[v] != d) continue;",
			"            for (auto [u, w] : adj[v]) {",
			"                if (dist[v] + w < dist[u]) {",
			"                    dist[u] = dist[v] + w;",
			"                    if (max_dist < 0 || dist[u] <= max_dist) {",
			"                        bucket[dist[u] % D].push_back(u);",
			"                        pending++;",
			"                    }",
			"                }",
			"            }",
			"        }",
			"        bucket[bi].clear();",
			"    }",
			"    return dist;",
			"}",
			""
		],
		"description": "dial"
	},
	"sa": {
		"prefix": "atcoder_ahc_sa",
		"body": [
			"// 焼きなまし法(Simulated Annealing)",
			"//",
			"// Usage:",
			"//   SA<ll> sa(start_temp, end_temp, time_limit);  // スコアの型を指定",
			"//",
			"//   // 基本パターン",
			"//   while (timer.elapsed() < time_limit) {",
			"//       double temp = sa.temperature();          // 温度を1回だけ取得",
			"//       ll diff = new_score - cur_score;         // diff > 0 が悪化(コスト最小化)",
			"//       if (sa.accept(diff, temp)) { /* 採用 */ }",
			"//   }",
			"//",
			"//   // 受理ライン(スコア計算を途中打ち切りするとき)",
			"//   double temp = sa.temperature();",
			"//   ll line = sa.threshold(temp);                // 先に受理ラインを確定",
			"//   ll new_score = 0;",
			"//   for (int i = 0; i < N; i++) {",
			"//       new_score += calc_partial(i);",
			"//       if (new_score - cur_score > line) break; // 越えると確定したら打ち切り",
			"//   }",
			"//   if (new_score - cur_score <= line) { /* 採用 */ }",
			"//",
			"//   // 温度スケジュール",
			"//   sa.temperature();         // 指数(デフォルト): 序盤に広く探索",
			"//   sa.temperature_linear();  // 線形: シンプル",
			"template<class T = double>",
			"struct SA {",
			"    double start_temp, end_temp, time_limit;",
			"",
			"    // -log(U), U~Uniform(0,1) のルックアップテーブル(分位点中点法)",
			"    struct MinusLogTable {",
			"        static constexpr int SIZE = 1 << 12;",
			"        double table[SIZE];",
			"        MinusLogTable() {",
			"            for (int i = 0; i < SIZE; i++)",
			"                table[i] = -log((i + 0.5) / SIZE);",
			"        }",
			"        double operator()() const {",
			"            return table[rng.random32(SIZE)];",
			"        }",
			"    } minus_log_table;",
			"",
			"    // 指数温度スケジュールのルックアップテーブル(構築時に事前計算)",
			"    struct TempTable {",
			"        static constexpr int SIZE = 1 << 12;",
			"        double table[SIZE];",
			"        void init(double start_temp, double end_temp) {",
			"            for (int i = 0; i < SIZE; i++)",
			"                table[i] = start_temp * pow(end_temp / start_temp, (i + 0.5) / SIZE);",
			"        }",
			"        double operator()(double ratio) const {",
			"            return table[min(SIZE - 1, (int)(ratio * SIZE))];",
			"        }",
			"    } temp_table;",
			"",
			"    SA(double start_temp, double end_temp, double time_limit)",
			"        : start_temp(start_temp), end_temp(end_temp), time_limit(time_limit) {",
			"        temp_table.init(start_temp, end_temp);",
			"    }",
			"",
			"    double ratio() const {",
			"        return min(1.0, (double)timer.elapsed() / time_limit);",
			"    }",
			"",
			"    double temperature() const {",
			"        return temp_table(ratio());",
			"    }",
			"    double temperature_linear() const {",
			"        return start_temp + (end_temp - start_temp) * ratio();",
			"    }",
			"",
			"    // diff <= threshold(temp) なら受理。先に1回呼んで途中打ち切りに使う。",
			"    T threshold(double temp) const { return static_cast<T>(temp * minus_log_table()); }",
			"    T threshold() const { return threshold(temperature()); }",
			"",
			"    // diff > 0 が悪化(コスト最小化)。threshold() と数学的に等価。",
			"    bool accept(T diff, double temp) const {",
			"        if (diff <= 0) return true;",
			"        return diff <= threshold(temp);",
			"    }",
			"    bool accept(T diff) const {",
			"        if (diff <= 0) return true;",
			"        return diff <= threshold(temperature());",
			"    }",
			"};"
		],
		"description": "sa"
	},
	"Bayes": {
		"prefix": "atcoder_ahc_Bayes",
		"body": [
			"// 離散ベイズ推定器。状態 0..N-1 の事後分布を log 空間で管理する。",
			"// likelihood[i] = P(obs | state=i) の計算は問題依存(ノイズモデルから導く)。",
			"//",
			"// Usage:",
			"//   BayesEstimator be(N);                        // 一様事前分布",
			"//   BayesEstimator be(prior);                    // カスタム事前分布 prior[i] = P(state=i)",
			"//   be.update(likelihood);                       // likelihood[i] = P(obs | state=i)",
			"//   be.update_log(log_likelihood);               // log尤度を直接渡す版(高速)",
			"//   double p = be.prob(i);                       // P(state=i | 全観測)",
			"//   int    s = be.argmax();                      // 最大事後確率の状態",
			"//   vector<double> ps = be.probs();              // 全確率を vector で取得",
			"//",
			"// 典型的な log 尤度の計算例(update_log に渡す):",
			"//   // ガウスノイズ: クエリに正規分布ノイズが乗る場合",
			"//   for (int i = 0; i < N; i++) log_lik[i] = -(obs-expected[i])*(obs-expected[i]) / (2*sigma*sigma);",
			"//",
			"//   // 二値ノイズ: 正解率 p で正しい答えが返ってくる場合",
			"//   for (int i = 0; i < N; i++) log_lik[i] = log(obs == true_val[i] ? p : 1.0-p);",
			"struct BayesEstimator {",
			"    int n;",
			"    vector<double> log_prob;",
			"",
			"    explicit BayesEstimator(int n) : n(n), log_prob(n, -log((double)n)) {}",
			"    explicit BayesEstimator(vector<double> prior) : n(prior.size()), log_prob(prior.size()) {",
			"        for (int i = 0; i < n; i++) log_prob[i] = log(prior[i]);",
			"        normalize();",
			"    }",
			"",
			"    void update(const vector<double>& likelihood) {",
			"        for (int i = 0; i < n; i++) log_prob[i] += log(likelihood[i]);",
			"        normalize();",
			"    }",
			"    void update_log(const vector<double>& log_likelihood) {",
			"        for (int i = 0; i < n; i++) log_prob[i] += log_likelihood[i];",
			"        normalize();",
			"    }",
			"",
			"    void normalize() {",
			"        double mx = *max_element(log_prob.begin(), log_prob.end());",
			"        double s = 0;",
			"        for (int i = 0; i < n; i++) s += exp(log_prob[i] - mx);",
			"        double log_s = mx + log(s);",
			"        for (int i = 0; i < n; i++) log_prob[i] -= log_s;",
			"    }",
			"",
			"    double prob(int i) const { return exp(log_prob[i]); }",
			"    int argmax() const { return max_element(log_prob.begin(), log_prob.end()) - log_prob.begin(); }",
			"    vector<double> probs() const {",
			"        vector<double> p(n);",
			"        for (int i = 0; i < n; i++) p[i] = prob(i);",
			"        return p;",
			"    }",
			"};"
		],
		"description": "Bayes"
	},
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define FOR(i,l,r) for (int i = l;i < (int)(r); i++)
#define rep(i,n) for (int i = 0;i < (int)(n); i++)
#define all(x) x.begin(), x.end()
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }

#ifdef LOCAL
    #include <debug_print.hpp>
    #define debug(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__)
#else
    #define debug(...) (static_cast<void>(0))
#endif

// 軽量な実行時間計測器。グローバルに timer が1つある。
// 時計を間引いて読むかは呼び出し側で決める。
//
// Usage:
//   timer.reset();                  // 計測開始時刻を現在時刻に戻す
//   float t = timer.elapsed();      // 計測開始からの経過時間を秒で返す
//
//   // 基本パターン
//   while (timer.elapsed() < time_limit) { ... }
//
//   // 時計の読み取りを間引く(近傍が軽くて秒間数百万回まわるとき)
//   if (cnt % 64 == 0 && timer.elapsed() >= time_limit) break;
struct Timer {
    Timer() { reset(); }

    void reset() { t_begin = chrono::steady_clock::now(); }

    float elapsed() const {
        return chrono::duration<float>(chrono::steady_clock::now() - t_begin).count();
    }

private:
    chrono::steady_clock::time_point t_begin;
} timer;

// xoroshiro128**。グローバルに rng が1つある(シード 345)。
// result_type / min() / max() / operator() を持つので、std の分布
// (uniform_int_distribution など) の engine としてもそのまま渡せる。
//
// Usage:
//   RNG my_rng(123);                             // シードを指定して作る
//   rng.reset(42);                               // シードを再設定する
//
//   // 整数
//   uint32_t a = rng();                          // 32bit 乱数。std の分布に渡す engine 用
//   uint32_t b = rng.random32(n);                // [0, n) の整数。n > 0
//   uint64_t c = rng.random64(n);                // [0, n) の整数(64bit)。n > 0
//   uint32_t d = rng.randomRange32(l, r);        // [l, r] の整数。両端を含む。l <= r
//   uint64_t e = rng.randomRange64(l, r);        // [l, r] の整数(64bit)。両端を含む
//
//   // 実数
//   double p = rng.randomDouble();               // [0, 1) の実数
//   float  q = rng.randomFloat();                // [0, 1) の実数(float)
//   double x = rng.randomRangeDouble(l, r);      // [l, r) の実数
//   double g = rng.randomGaussian(mean, stddev); // 正規分布 N(mean, stddev^2)。既定は N(0, 1)
//
//   // コンテナ
//   rng.shuffle(v);                              // vector をシャッフルする
//   rng.shuffle(a, a + n);                       // [fr, to) をシャッフルする
//   int  i = rng.sample_index(v);                // 添字を一様に選ぶ。v は非空
//   auto y = rng.sample(v);                      // 要素を一様に選ぶ。v は非空
struct RNG {
    using result_type = uint32_t;
    static constexpr uint32_t min() { return 0; }
    static constexpr uint32_t max() { return numeric_limits<uint32_t>::max(); }

    RNG(uint64_t seed) { reset(seed); }
    RNG() { reset(time(0)); }

    void reset(uint64_t seed) {
        struct splitmix64_state {
            uint64_t s;
            uint64_t splitmix64() {
                uint64_t result = (s += 0x9E3779B97f4A7C15);
                result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9;
                result = (result ^ (result >> 27)) * 0x94D049BB133111EB;
                return result ^ (result >> 31);
            }
        };
        splitmix64_state sm{seed};
        s[0] = sm.splitmix64();
        s[1] = sm.splitmix64();
    }

    uint32_t operator()() { return next32(); }
    uint32_t random32(uint32_t r) { return (uint64_t(next32()) * r) >> 32; }
    uint64_t random64(uint64_t r) { return uint64_t((__uint128_t(next64()) * r) >> 64); }
    uint32_t randomRange32(uint32_t l, uint32_t r) { return l + random32(r - l + 1); }
    uint64_t randomRange64(uint64_t l, uint64_t r) { return l + random64(r - l + 1); }

    double randomDouble() { return double(next32()) / 4294967296.0; }
    float randomFloat() { return float(next32()) / 4294967296.0f; }
    double randomRangeDouble(double l, double r) { return l + randomDouble() * (r - l); }
    double randomGaussian(double mean = 0.0, double stddev = 1.0) {
        double u1 = (next32() + 1.0) / 4294967297.0;
        double u2 = randomDouble();
        return mean + stddev * sqrt(-2.0 * log(u1)) * cos(2.0 * 3.141592653589793238 * u2);
    }

    template <class T> void shuffle(vector<T>& v) {
        for (int i = (int)v.size(); i > 1; i--) swap(v[i - 1], v[random32(i)]);
    }
    template <class T> void shuffle(T* fr, T* to) {
        int sz = (int)distance(fr, to);
        for (int i = sz; i > 1; i--) swap(fr[i - 1], fr[random32(i)]);
    }
    template <class T> int sample_index(const vector<T>& v) { return random32((uint32_t)v.size()); }
    template <class T> T sample(const vector<T>& v) { return v[sample_index(v)]; }

private:
    uint64_t s[2];
    static uint64_t rotl(uint64_t x, int k) { return (x << k) | (x >> (64 - k)); }
    uint64_t next64() {
        const uint64_t s0 = s[0];
        uint64_t s1 = s[1];
        const uint64_t result = rotl(s0 * 5, 7) * 9;
        s1 ^= s0;
        s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16);
        s[1] = rotl(s1, 37);
        return result;
    }
    uint32_t next32() { return (uint32_t)next64(); }
} rng(345);

// 焼きなまし法(Simulated Annealing)。スコアの型 T を指定する。
// コスト最小化。スコア最大化のときは accept(cur - neu, temp) と符号を反転させる。
// end_temp は正であること(指数スケジュールの pow のため)。
// 構築時に開始時刻を1回記録する。進捗は (now - 開始) / (end_time - 開始)。
// end_time は timer.elapsed() と同じ時計での終了時刻。温度の間引きは Solver 側で行う。
//
// Usage:
//   SA<ll> sa(start_temp, end_temp, end_time);  // 例: end_time = 2.85
//
//   double t1 = sa.temperature();         // 指数スケジュールの温度。序盤に広く探索する
//   double t2 = sa.temperature_linear();  // 線形スケジュールの温度
//   ll line = sa.threshold(temp);         // 受理ライン。diff <= line なら受理
//   bool ok = sa.accept(diff, temp);      // diff > 0 が悪化。温度は呼び出し側で1回取って渡す
//
//   // 基本パターン
//   while (timer.elapsed() < end_time) {
//       double temp = sa.temperature();          // 温度は1回だけ取る
//       ll diff = new_score - cur_score;         // diff > 0 が悪化
//       if (sa.accept(diff, temp)) { /* 採用 */ }
//   }
//
//   // 受理ライン(スコア計算を途中打ち切りするとき)
//   double temp = sa.temperature();
//   ll line = sa.threshold(temp);                // 先に受理ラインを確定させる
//   ll new_score = 0;
//   for (int i = 0; i < N; i++) {
//       new_score += calc_partial(i);
//       if (new_score - cur_score > line) break; // 越えると確定したら打ち切る
//   }
//   if (new_score - cur_score <= line) { /* 採用 */ }
template<class T = double>
struct SA {
    double start_temp, end_temp, end_time;

    SA(double start_temp, double end_temp, double end_time)
        : start_temp(start_temp), end_temp(end_temp), end_time(end_time),
          t_begin(timer.elapsed()) {
        for (int i = 0; i < TABLE_SIZE; i++) {
            minus_log_table[i] = -log((i + 0.5) / TABLE_SIZE);
            temp_table[i] = start_temp * pow(end_temp / start_temp, (i + 0.5) / TABLE_SIZE);
        }
    }

    double temperature() const {
        return temp_table[min(TABLE_SIZE - 1, (int)(ratio() * TABLE_SIZE))];
    }
    double temperature_linear() const {
        return start_temp + (end_temp - start_temp) * ratio();
    }
    T threshold(double temp) const {
        return static_cast<T>(temp * minus_log_table[rng.random32(TABLE_SIZE)]);
    }
    bool accept(T diff, double temp) const {
        if (diff <= 0) return true;
        return diff <= threshold(temp);
    }

private:
    static constexpr int TABLE_SIZE = 1 << 12;
    double minus_log_table[TABLE_SIZE];
    double temp_table[TABLE_SIZE];
    double t_begin;

    double ratio() const {
        double dur = end_time - t_begin;
        if (dur <= 0) return 1.0;
        return min(1.0, (timer.elapsed() - t_begin) / dur);
    }
};

// open addressing, linear probing。unordered_map より高速。
// Key にはハッシュ適用済みの値を渡す。
//
// Usage:
//   HashMap<uint64_t, int> seen(beam_width * 16);  // n は格納要素数の 16 倍程度
//
//   auto [exists, idx] = seen.get_index(hash);  // {存在するか, slot}。set/get には slot を渡す
//   seen.set(idx, hash, node_id);               // slot に (key, value) を書く
//   int v = seen.get(idx);                      // slot の値を返す
//   seen.clear();                               // 中身を捨てる。O(1)
//
//   // 基本パターン(ビームサーチの重複除去)
//   auto [exists, idx] = seen.get_index(hash);
//   if (!exists) seen.set(idx, hash, node_id);
//   seen.clear();  // 次ターンへ
template<class Key, class T>
struct HashMap {
    explicit HashMap(uint32_t n) {
        if (n % 2 == 0) ++n;
        n_ = n;
        stamp_.assign(n_, 0);
        data_.resize(n_);
    }

    pair<bool, int> get_index(Key key) const {
        uint32_t i = (uint32_t)(key % n_);
        uint32_t start = i;
        while (stamp_[i] == current_stamp_) {
            if (data_[i].first == key) return {true, (int)i};
            if (++i == n_) i = 0;
            if (i == start) return {false, (int)i};
        }
        return {false, (int)i};
    }
    void set(int i, Key key, T value) {
        stamp_[i] = current_stamp_;
        data_[i] = {key, value};
    }

    T get(int i) const { return data_[i].second; }

    void clear() {
        if (++current_stamp_ == 0) {
            fill(stamp_.begin(), stamp_.end(), 0);
            current_stamp_ = 1;
        }
    }

private:
    uint32_t n_;
    uint32_t current_stamp_ = 1;
    vector<uint32_t> stamp_;
    vector<pair<Key, T>> data_;
};

// 整数集合 [0, n) に対する insert / erase / next / prev が O(log n / log 64) の 64 分木。
// std::set<int> より高速。
//
// Usage:
//   FastSet fs(N);            // 宇宙 [0, N) の空集合を作る
//
//   fs.insert(i);             // i を追加する
//   fs.erase(i);              // i を削除する
//   bool b = fs.contains(i);  // i が含まれるか。O(1)
//   bool e = fs.empty();      // 空なら true
//   int x = fs.next(i);       // i 以上の最小値。なければ N
//   int y = fs.prev(i);       // i 以下の最大値。なければ -1
//   int mn = fs.min_val();    // 最小値。空なら N
//   int mx = fs.max_val();    // 最大値。空なら -1
//
//   // 基本パターン(残っている要素を昇順に舐める)
//   for (int i = fs.min_val(); i < N; i = fs.next(i + 1)) { ... }
struct FastSet {
    FastSet() : n_(0), log_(0) {}

    explicit FastSet(int n) : n_(n), log_(0) {
        if (n == 0) return;
        int m = n;
        do {
            d_.push_back(vector<uint64_t>((m + B - 1) / B, 0));
            m = (m + B - 1) / B;
        } while (m > 1);
        log_ = (int)d_.size();
    }
    void insert(int i) {
        for (int h = 0; h < log_; h++) {
            d_[h][i / B] |= 1ULL << (i % B);
            i /= B;
        }
    }

    void erase(int i) {
        for (int h = 0; h < log_; h++) {
            d_[h][i / B] &= ~(1ULL << (i % B));
            if (d_[h][i / B]) break;
            i /= B;
        }
    }
    bool contains(int i) const {
        if (log_ == 0) return false;
        return (d_[0][i / B] >> (i % B)) & 1;
    }

    bool empty() const { return log_ == 0 || d_[log_ - 1][0] == 0; }

    int next(int i) const {
        for (int h = 0; h < log_; h++) {
            int b = i / B;
            if (b >= (int)d_[h].size()) break;
            uint64_t f = d_[h][b] >> (i % B);
            if (!f) { i = b + 1; continue; }
            i += __builtin_ctzll(f);
            for (int g = h - 1; g >= 0; g--)
                i = i * B + __builtin_ctzll(d_[g][i]);
            return i;
        }
        return n_;
    }
    int prev(int i) const {
        for (int h = 0; h < log_; h++) {
            if (i < 0) break;
            int b = i / B;
            uint64_t f = d_[h][b] << (B - 1 - i % B);
            if (!f) { i = b - 1; continue; }
            i -= __builtin_clzll(f);
            for (int g = h - 1; g >= 0; g--)
                i = i * B + 63 - __builtin_clzll(d_[g][i]);
            return i;
        }
        return -1;
    }
    int min_val() const { return next(0); }
    int max_val() const { return prev(n_ - 1); }

private:
    static constexpr int B = 64;
    int n_, log_;
    vector<vector<uint64_t>> d_;
};

// 3x3 局所連結性。あるマスを消したとき、周囲の物体が分裂するかを判定する。
//
// 見ているもの:
//   中心 C は見ない。周囲 8 マスだけを「物体 / 空」に分け、C を除いたあとの
//   連結成分数が 2 以上なら分裂(消せない)。0 または 1 ならつながったまま(消せる)。
//
//   0 1 2
//   3 C 4
//   5 6 7
//
// 引数:
//   grid : 2次元配列。grid[row][col] が真なら物体、偽なら空。
//          0/1 の int、bool など、if (grid[r][c]) が使える型なら何でもよい。
//          盤のサイズは grid.size() と grid[0].size() から取る。
//   r, c : 消したいマス(0-index)。このマス自身の値は使わない。
//
// conn8=true  : 斜めもつながる(8連結)
// conn8=false : 上下左右だけ(4連結)
//
// Usage:
//   ConnTable<>      conn_table;  // 8連結(グローバルに1つ用意してある)
//   ConnTable<false> conn4;       // 4連結
//
//   bool ok = conn_table.can_remove(grid, r, c);  // (r,c) を消しても分裂しないなら true
//
//   // 基本パターン
//   if (conn_table.can_remove(grid, r, c)) grid[r][c] = 0;
template<bool conn8 = true>
struct ConnTable {
    ConnTable() {
        for (int mask = 0; mask < 256; mask++) table[mask] = count_components(mask);
    }

    template<class Grid>
    bool can_remove(const Grid& grid, int r, int c) const {
        int H = (int)grid.size();
        int W = H ? (int)grid[0].size() : 0;
        return table[neighbors(grid, r, c, H, W)] <= 1;
    }

private:
    uint8_t table[256];
    template<class Grid>
    uint8_t neighbors(const Grid& grid, int r, int c, int H, int W) const {
        static const int dr[] = {-1,-1,-1, 0, 0, 1, 1, 1};
        static const int dc[] = {-1, 0, 1,-1, 1,-1, 0, 1};
        uint8_t mask = 0;
        for (int k = 0; k < 8; k++) {
            int nr = r + dr[k], nc = c + dc[k];
            if (nr >= 0 && nr < H && nc >= 0 && nc < W && grid[nr][nc])
                mask |= 1 << k;
        }
        return mask;
    }
    static int count_components(int mask) {
        static const int adj8[8][4] = {
            {1, 3, -1, -1}, {0, 2, 3, 4}, {1, 4, -1, -1}, {0, 1, 5, 6},
            {1, 2, 6, 7}, {3, 6, -1, -1}, {3, 4, 5, 7}, {4, 6, -1, -1},
        };
        static const int adj4[8][4] = {
            {1, 3, -1, -1}, {0, 2, -1, -1}, {1, 4, -1, -1}, {0, 5, -1, -1},
            {2, 7, -1, -1}, {3, 6, -1, -1}, {5, 7, -1, -1}, {4, 6, -1, -1},
        };
        const auto& adj = conn8 ? adj8 : adj4;
        int comp = 0;
        uint8_t visited = 0;
        for (int i = 0; i < 8; i++) {
            if (!((mask >> i) & 1) || (visited >> i) & 1) continue;
            comp++;
            uint8_t stk = 1 << i;
            visited |= 1 << i;
            while (stk) {
                int u = __builtin_ctz(stk);
                stk &= stk - 1;
                for (int k = 0; k < 4 && adj[u][k] != -1; k++) {
                    int v = adj[u][k];
                    if (((mask >> v) & 1) && !((visited >> v) & 1)) {
                        visited |= 1 << v;
                        stk |= 1 << v;
                    }
                }
            }
        }
        return comp;
    }
};
ConnTable<> conn_table;  // 8連結。4連結が必要なら ConnTable<false> を別途宣言する。

// 離散ベイズ推定器。状態 0..n-1 の事後分布を log 空間で管理する。
// likelihood[i] = P(obs | state=i) の計算は問題依存(ノイズモデルから導く)。
//
// Usage:
//   BayesEstimator be(N);                        // 一様事前分布
//   BayesEstimator be(prior);                    // カスタム事前分布 prior[i] = P(state=i)
//   be.update(likelihood);                       // likelihood[i] = P(obs | state=i)
//   be.update_log(log_likelihood);               // log 尤度を直接渡す版
//   double p = be.prob(i);                       // P(state=i | 全観測)
//   int    s = be.argmax();                      // 最大事後確率の状態
//   vector<double> ps = be.probs();              // 全確率を vector で返す
//
// 典型的な log 尤度(update_log に渡す):
//   // ガウスノイズ
//   for (int i = 0; i < N; i++) log_lik[i] = -(obs-expected[i])*(obs-expected[i]) / (2*sigma*sigma);
//   // 二値ノイズ(正解率 p)
//   for (int i = 0; i < N; i++) log_lik[i] = log(obs == true_val[i] ? p : 1.0-p);
struct BayesEstimator {
    explicit BayesEstimator(int n) : n(n), log_prob(n, -log((double)n)) {}
    explicit BayesEstimator(vector<double> prior)
        : n((int)prior.size()), log_prob(prior.size()) {
        for (int i = 0; i < n; i++) log_prob[i] = log(prior[i]);
        normalize();
    }

    void update(const vector<double>& likelihood) {
        for (int i = 0; i < n; i++) log_prob[i] += log(likelihood[i]);
        normalize();
    }

    void update_log(const vector<double>& log_likelihood) {
        for (int i = 0; i < n; i++) log_prob[i] += log_likelihood[i];
        normalize();
    }

    double prob(int i) const { return exp(log_prob[i]); }
    int argmax() const { return int(max_element(log_prob.begin(), log_prob.end()) - log_prob.begin()); }

    vector<double> probs() const {
        vector<double> p(n);
        for (int i = 0; i < n; i++) p[i] = prob(i);
        return p;
    }

private:
    int n;
    vector<double> log_prob;
    void normalize() {
        double mx = *max_element(log_prob.begin(), log_prob.end());
        double s = 0;
        for (int i = 0; i < n; i++) s += exp(log_prob[i] - mx);
        double log_s = mx + log(s);
        for (int i = 0; i < n; i++) log_prob[i] -= log_s;
    }
};

// Dial's アルゴリズム(バケットキュー)。辺コストが小さい整数のとき priority_queue より高速。
// max_cost = 最大辺コスト(BFS なら 1)
// max_dist = 探索する最大距離(省略時は全到達頂点を探索)
// 未到達は INT_MAX。
//
// Usage:
//   vector<vector<pair<int,int>>> adj(N);  // adj[v] = {{隣接, 重み}, ...}
//   auto dist = dial(start, N, adj, 1);                    // BFS
//   auto dist = dial(start, N, adj, max_cost);             // 全頂点
//   auto dist = dial(start, N, adj, max_cost, max_dist);   // 距離 max_dist 以内
vector<int> dial(int start, int n, const vector<vector<pair<int, int>>>& adj,
                 int max_cost, int max_dist = -1) {
    const int D = max_cost + 1;
    vector<int> dist(n, INT_MAX);
    vector<vector<int>> bucket(D);
    dist[start] = 0;
    bucket[0].push_back(start);
    int pending = 1;
    for (int d = 0; pending > 0; d++) {
        int bi = d % D;
        for (size_t k = 0; k < bucket[bi].size(); k++) {
            int v = bucket[bi][k];
            if (dist[v] != d) continue;
            for (auto [u, w] : adj[v]) {
                if (dist[v] + w < dist[u]) {
                    dist[u] = dist[v] + w;
                    if (max_dist < 0 || dist[u] <= max_dist) {
                        bucket[dist[u] % D].push_back(u);
                        pending++;
                    }
                }
            }
        }
        pending -= (int)bucket[bi].size();
        bucket[bi].clear();
    }
    return dist;
}

struct Solver {
    Solver() { timer.reset(); }

    void read() {}

    void solve() {}

    void print() const {}
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    Solver solver;
    solver.read();
    solver.solve();
    solver.print();
    return 0;
}