// Begin include: "../../template/template.hpp" using namespace std; // intrinstic #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Begin include: "util.hpp" namespace yamada { using ll = long long; using i32 = int; using u32 = unsigned int; using i64 = long long; using u64 = unsigned long long; using i128 = __int128_t; using u128 = __uint128_t; using lld = long double; template using vc = vector; template using VV = vector>; template using VVV = vector>>; template using VVVV = vector>>>; using vl = vector; using vd = vector; using vs = vector; using vb = vector; using vvl = vector>; using vvvl = vector>>; using vvvvl = vector>>>; template using minpq = priority_queue, greater>; template using maxpq = priority_queue, less>; template struct pr : pair { template pr(Args... args) : pair(args...) {} using pair::first; using pair::second; pr &operator+=(const pr &r) { first += r.first; second += r.second; return *this; } pr &operator-=(const pr &r) { first -= r.first; second -= r.second; return *this; } pr &operator*=(const pr &r) { first *= r.first; second *= r.second; return *this; } template pr &operator*=(const S &r) { first *= r, second *= r; return *this; } pr operator+(const pr &r) const { return pr(*this) += r; } pr operator-(const pr &r) const { return pr(*this) -= r; } pr operator*(const pr &r) const { return pr(*this) *= r; } template pr operator*(const S &r) const { return pr(*this) *= r; } pr operator-() const { return pr{-first, -second}; } }; using pl = pr; using vp = vc; using vvp = VV; constexpr int inf = 1001001001; constexpr long long infLL = 4004004004004004004LL; template inline bool amin(T &x, U y) { return (y < x) ? (x = y, true) : false; } template inline bool amax(T &x, U y) { return (x < y) ? (x = y, true) : false; } template inline T Max(const vector &v) { return *max_element(begin(v), end(v)); } template inline T Min(const vector &v) { return *min_element(begin(v), end(v)); } template inline long long Sum(const vector &v) { return accumulate(begin(v), end(v), T(0)); } template int lb(const vector &v, const T &a) { return lower_bound(begin(v), end(v), a) - begin(v); } template int ub(const vector &v, const T &a) { return upper_bound(begin(v), end(v), a) - begin(v); } constexpr long long TEN(int n) { long long ret = 1, x = 10; for (; n; x *= x, n >>= 1) ret *= (n & 1 ? x : 1); return ret; } template vector mkrui(const vector &v, bool rev = false) { vector ret(v.size() + 1); if (rev) { for (int i = int(v.size()) - 1; i >= 0; i--) ret[i] = v[i] + ret[i + 1]; } else { for (int i = 0; i < int(v.size()); i++) ret[i + 1] = ret[i] + v[i]; } return ret; }; template vector mkuni(const vector &v) { vector ret(v); sort(ret.begin(), ret.end()); ret.erase(unique(ret.begin(), ret.end()), ret.end()); return ret; } template vector mkord(int n, F f) { vector ord(n); iota(begin(ord), end(ord), 0); sort(begin(ord), end(ord), f); return ord; } template vector mkinv(vector &v) { int max_val = *max_element(begin(v), end(v)); vector inv(max_val + 1, -1); for (int i = 0; i < (int)v.size(); i++) inv[v[i]] = i; return inv; } vector mkiota(int n) { vector ret(n); iota(ret.begin(), ret.end(), 0); return ret; } // g o f vector p_mrg(vector f, const vector &g) { for (int i = 0; i < (int)f.size(); i++) f[i]=g[f[i]]; return f; } // f: old_idx -> new_idx template vector p_shf(const vector& f, const vector& A, const bool inv = false) { int n = A.size(); vector ret(n); if (!inv) for (int i = 0; i < n; i++) ret[f[i]] = A[i]; else for (int i = 0; i < n; i++) ret[i] = A[f[i]]; return ret; } template T mkrev(const T &v) { T w{v}; reverse(begin(w), end(w)); return w; } template bool nxp(T &v) { return std::next_permutation(begin(v), end(v)); } template void nxp(int n, F f) { vector a(n); iota(begin(a), end(a), 0); do { f(a); } while (nxp(a)); } // 返り値の型は入力の T に依存 // i 要素目 : [0, a[i]) template vector> product(const vector &a) { vector> ret; vector v; auto dfs = [&](auto rc, int i) -> void { if (i == (int)a.size()) { ret.push_back(v); return; } for (int j = 0; j < a[i]; j++) v.push_back(j), rc(rc, i + 1), v.pop_back(); }; dfs(dfs, 0); return ret; } template vector Digit(T a, const U &x, int siz = -1) { vector ret; while (a > 0) { ret.emplace_back(a % x); a /= x; } if (siz >= 0) while ((int)ret.size() < siz) ret.emplace_back(0); return ret; } // F : function(void(T&)), mod を取る操作 // T : 整数型のときはオーバーフローに注意する template T Power(T a, long long n, const T &I, const function &f) { T res = I; for (; n; f(a = a * a), n >>= 1) { if (n & 1) f(res = res * a); } return res; } // T : 整数型のときはオーバーフローに注意する template T Power(T a, long long n, const T &I = T{1}) { return Power(a, n, I, function{[](T &) -> void {}}); } template T Rev(const T &v) { T res = v; reverse(begin(res), end(res)); return res; } template vector Transpose(const vector &v) { using U = typename T::value_type; if(v.empty()) return {}; int H = v.size(), W = v[0].size(); vector res(W, T(H, U{})); for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) res[j][i] = v[i][j]; return res; } template vector Rotate(const vector &v, int clockwise = true) { using U = typename T::value_type; int H = v.size(), W = v[0].size(); vector res(W, T(H, U{})); for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) { if (clockwise) res[W - 1 - j][i] = v[i][j]; else res[j][H - 1 - i] = v[i][j]; } return res; } template T bisect(T ok, T bad, F pred) { if (ok == bad) return ok; while (bad - ok > 1) { T mid = ok + (bad - ok) / 2; (pred(mid) ? ok : bad) = mid; } return bad; } template T bisect_double(T ok, T bad, F pred, int iter = 100) { if (ok == bad) return ok; while (iter--) { T mid = ok + (bad - ok) / 2; (pred(mid) ? ok : bad) = mid; } return bad; } template bool inLR(T L, T x, T R){ return (L <= x && x < R); } bool YESNO(bool b) { std::cout << (b ? "YES\n" : "NO\n"); return b; } bool YesNo(bool b) { std::cout << (b ? "Yes\n" : "No\n"); return b; } bool yesno(bool b) { std::cout << (b ? "yes\n" : "no\n"); return b; } bool is_square(uint64_t n) { if (n < 2) return true; uint64_t r = static_cast(sqrtl(static_cast(n))); if (r * r == n) return true; ++r; return r * r == n; } template struct CumulativeSum { std::vector S; CumulativeSum(std::vector &A) { int N = A.size(); S.resize(N + 1); for (int i = 0; i < N; i++) S[i + 1] = S[i] + A[i]; } T query(int l, int r) { return (l <= r ? S[r] - S[l] : (T)0); } T query() { return S.back(); } inline T operator()(int l, int r) { return query(l, r); } inline T operator()() { return query(); } }; long long Floor(long long a, long long b) { assert(b != 0); if (b < 0) a = -a, b = -b; return a / b - (a % b < 0); } long long Under(long long a, long long b) { assert(b != 0); if (b < 0) a = -a, b = -b; return a / b - (a % b <= 0); } long long Ceil(long long a, long long b) { assert(b != 0); if (b < 0) a = -a, b = -b; return a / b + (a % b > 0); } long long Over(long long a, long long b) { assert(b != 0); if (b < 0) a = -a, b = -b; return a / b + (a % b >= 0); } long long Modulo(long long a, long long b) { assert(b > 0); long long c = a % b; return c < 0 ? c + b : c; } } // namespace yamada // End include: "util.hpp" // Begin include: "bitop.hpp" namespace yamada { __attribute__((target("popcnt"))) inline int popcnt(const u64 &a) { return __builtin_popcountll(a); } inline int lsb(const u64 &a) { return a ? __builtin_ctzll(a) : 64; } inline int msb(const u64 &a) { return a ? 63 - __builtin_clzll(a) : -1; } template inline int gbit(const T &a, int i) { return (a >> i) & 1; } template inline void sbit(T &a, int i, bool b) { if (gbit(a, i) != b) a ^= T(1) << i; } constexpr long long PW(int n) { return 1LL << n; } constexpr long long MSK(int n) { return (1LL << n) - 1; } } // namespace yamada // End include: "bitop.hpp" // Begin include: "inout.hpp" namespace yamada { template ostream &operator<<(ostream &os, const array &v); template istream &operator>>(istream &is, array &v); template ostream &operator<<(ostream &os, const vector &v); template istream &operator>>(istream &is, vector &v); template ostream &operator<<(ostream &os, const pair &p); template istream &operator>>(istream &is, pair &p); template ostream &operator<<(ostream &os, const pair &p) { os << p.first << " " << p.second; return os; } template istream &operator>>(istream &is, pair &p) { is >> p.first >> p.second; return is; } template ostream &operator<<(ostream &os, const vector &v) { int s = (int)v.size(); for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i]; return os; } template istream &operator>>(istream &is, vector &v) { for (auto &x : v) is >> x; return is; } template ostream &operator<<(ostream &os, const array &v) { for (int i = 0; i < K; i++) os << (i ? " " : "") << v[i]; return os; } template istream &operator>>(istream &is, array &v) { for (auto &x : v) is >> x; return is; } istream &operator>>(istream &is, __int128_t &x) { string S; is >> S; x = 0; int flag = 0; for (auto &c : S) { if (c == '-') { flag = true; continue; } x *= 10; x += c - '0'; } if (flag) x = -x; return is; } istream &operator>>(istream &is, __uint128_t &x) { string S; is >> S; x = 0; for (auto &c : S) { x *= 10; x += c - '0'; } return is; } ostream &operator<<(ostream &os, __int128_t x) { if (x == 0) return os << 0; if (x < 0) os << '-', x = -x; string S; while (x) S.push_back('0' + x % 10), x /= 10; reverse(begin(S), end(S)); return os << S; } ostream &operator<<(ostream &os, __uint128_t x) { if (x == 0) return os << 0; string S; while (x) S.push_back('0' + x % 10), x /= 10; reverse(begin(S), end(S)); return os << S; } void in() {} template void in(T &t, U &...u) { cin >> t; in(u...); } void out() { cout << "\n"; } template void out(const T &t, const U &...u) { cout << t; if constexpr (sizeof...(u)) { cout << sep; out(u...); } else out(); } void fout() { cout << endl; } template void fout(const T &t, const U &...u) { cout << t; if constexpr (sizeof...(u)) { cout << sep; fout(u...); } else fout(); } void wout() {} template void wout(const T &t, const U &...u) { cout << t; if constexpr (sizeof...(u)) { cout << sep; wout(u...); } else wout(); } template std::string toFraction(const mint &a) { for (int deno = 1; deno <= iter; deno++) { mint inv = ((mint)deno).inverse(); for (int nume = 0; nume <= iter; nume++) { mint val = inv * nume; if (val == a) { if (deno == 1) return std::to_string(nume); return std::to_string(nume) + "/" + std::to_string(deno); } else if (-val == a) { if (deno == 1) return std::to_string(-nume); return std::to_string(-nume) + "/" + std::to_string(deno); } } } return "NF"; } void mout() { cout << endl; } template void mout(const mint &a, const U &...u) { std::cout << toFraction(a); if constexpr (sizeof...(u)) { cout << sep; mout(u...); } else mout(); } template void mout(std::vector &A) { for (int i = 0; i < (int)A.size(); i++) { std::cout << toFraction(A[i], iter) << (i == (int)A.size() - 1 ? "\n" : " "); } } struct IoSetupYamada { IoSetupYamada() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(15); cerr << fixed << setprecision(7); } } iosetupyamada; } // namespace yamada // End include: "inout.hpp" // Begin include: "debug.hpp" namespace DebugImpl { template struct is_specialize : false_type {}; template struct is_specialize< U, typename conditional::type> : true_type {}; template struct is_specialize< U, typename conditional::type> : true_type {}; template struct is_specialize::value, void>> : true_type {}; void dump(const char& t) { cerr << t; } void dump(const string& t) { cerr << t; } void dump(const bool& t) { cerr << (t ? "true" : "false"); } void dump(__int128_t t) { if (t == 0) cerr << 0; if (t < 0) cerr << '-', t = -t; string S; while (t) S.push_back('0' + t % 10), t /= 10; reverse(begin(S), end(S)); cerr << S; } void dump(__uint128_t t) { if (t == 0) cerr << 0; string S; while (t) S.push_back('0' + t % 10), t /= 10; reverse(begin(S), end(S)); cerr << S; } template ::value, nullptr_t> = nullptr> void dump(const U& t) { cerr << t; } template void dump(const T& t, enable_if_t::value>* = nullptr) { string res; if (t == yamada::inf) res = "inf"; if constexpr (is_signed::value) { if (t == -yamada::inf) res = "-inf"; } if constexpr (sizeof(T) == 8) { if (t == yamada::infLL) res = "inf"; if constexpr (is_signed::value) { if (t == -yamada::infLL) res = "-inf"; } } if (res.empty()) res = to_string(t); cerr << res; } template void dump(const pair&); template void dump(const pair&); template void dump(const T& t, enable_if_t::value>* = nullptr) { cerr << "[ "; for (auto it = t.begin(); it != t.end();) { dump(*it); cerr << (++it == t.end() ? "" : ", "); } cerr << " ]"; } template void dump(const pair& t) { cerr << "( "; dump(t.first); cerr << ", "; dump(t.second); cerr << " )"; } template void dump(const pair& t) { cerr << "[ "; for (int i = 0; i < t.second; i++) { dump(t.first[i]); cerr << (i == t.second - 1 ? "" : ", "); } cerr << " ]"; } void trace() { cerr << endl; } template void trace(Head&& head, Tail&&... tail) { cerr << " "; dump(head); if (sizeof...(tail) != 0) cerr << ","; trace(std::forward(tail)...); } } // namespace DebugImpl #define yamadaDebug #ifdef yamadaDebug #define err(...) \ do { \ cerr << "## " << #__VA_ARGS__ << " = "; \ DebugImpl::trace(__VA_ARGS__); \ } while (0) #else #define err(...) (void(0)) #endif // End include: "debug.hpp" // Begin include: "macro.hpp" #define each1(x, v) for (auto&& x : v) #define each2(x, y, v) for (auto&& [x, y] : v) #define each3(x, y, z, v) for (auto&& [x, y, z] : v) #define each4(x, y, z, w, v) for (auto&& [x, y, z, w] : v) #define overload5(a, b, c, d, e, f, ...) f #define each(...) overload5(__VA_ARGS__, each4, each3, each2, each1)(__VA_ARGS__) #define rep1(a) for (long long _ = 0; _ < (long long)(a); ++_) #define rep2(i, a) for (long long i = 0; i < (long long)(a); ++i) #define rep3(i, a, b) for (long long i = a; i < (long long)(b); ++i) #define rep4(i, a, b, c) for (long long i = a; i < (long long)(b); i += c) #define overload4(a, b, c, d, e, ...) e #define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__) #define rep1r(a) for (long long i = (long long)(a)-1; i >= 0LL; --i) #define rep2r(i, a) for (long long i = (long long)(a)-1; i >= 0LL; --i) #define rep3r(i, a, b) for (long long i = (long long)(b)-1; i >= (long long)(a); --i) #define overload3(a, b, c, d, ...) d #define repr(...) overload3(__VA_ARGS__, rep3r, rep2r, rep1r)(__VA_ARGS__) #define all(v) (v).begin(), (v).end() #define eb emplace_back #define mkp make_pair #define mkt make_tuple #define fi first #define se second #define vv(type, name, h, ...) \ vector > name(h, vector(__VA_ARGS__)) #define vvv(type, name, h, w, ...) \ vector>> name( \ h, vector>(w, vector(__VA_ARGS__))) #define vvvv(type, name, a, b, c, ...) \ vector>>> name( \ a, vector>>( \ b, vector>(c, vector(__VA_ARGS__)))) #define ini(...) \ int __VA_ARGS__; \ in(__VA_ARGS__) #define inl(...) \ long long __VA_ARGS__; \ in(__VA_ARGS__) #define ins(...) \ string __VA_ARGS__; \ in(__VA_ARGS__) #define in2(s, t) \ for (int i = 0; i < (int)s.size(); i++) { \ in(s[i], t[i]); \ } #define in3(s, t, u) \ for (int i = 0; i < (int)s.size(); i++) { \ in(s[i], t[i], u[i]); \ } #define in4(s, t, u, v) \ for (int i = 0; i < (int)s.size(); i++) { \ in(s[i], t[i], u[i], v[i]); \ } #define die(...) \ do { \ yamada::out(__VA_ARGS__);\ return; \ } while (0) // End include: "macro.hpp" namespace yamada { void solve(); } int main() { yamada::solve(); } // End include: "../../template/template.hpp" // Begin include: "../../graph/namori.hpp" #include // Begin include: "../data-structure/union-find.hpp" struct UnionFind { vector data, nxt; UnionFind(int N) : data(N, -1), nxt(N) { for (int i = 0; i < N; i++) nxt[i] = i; } int find(int k) { return data[k] < 0 ? k : data[k] = find(data[k]); } int unite(int x, int y) { if ((x = find(x)) == (y = find(y))) return false; if (data[x] > data[y]) swap(x, y); data[x] += data[y]; data[y] = x; swap(nxt[x], nxt[y]); return true; } // f(x, y) : x に y をマージ template int unite(int x, int y, const F &f) { if ((x = find(x)) == (y = find(y))) return false; if (data[x] > data[y]) swap(x, y); data[x] += data[y]; data[y] = x; f(x, y); swap(nxt[x], nxt[y]); return true; } // g(x, y) : y に x をマージ template int unite(int x, int y, const F &f, const G &g) { if ((x = find(x)) == (y = find(y))) return false; if (data[x] > data[y]) { g(x, y); swap(x, y); } else f(x, y); data[x] += data[y]; data[y] = x; return true; } int size(int k) { return -data[find(k)]; } int same(int x, int y) { return find(x) == find(y); } vector enumerate(int i) { vector res{i}; for (int j = nxt[i]; j != i; j = nxt[j]) res.push_back(j); return res; } vector > groups() { vector > ret; for (int i = 0; i < (int)data.size(); ++i) if (i == find(i)) { ret.emplace_back(enumerate(i)); } return ret; } }; // End include: "../data-structure/union-find.hpp" // Begin include: "../tree/heavy-light-decomposition.hpp" // Begin include: "../graph/graph-template.hpp" template struct edge { int src, to; T cost; edge(int _to, T _cost) : src(-1), to(_to), cost(_cost) {} edge(int _src, int _to, T _cost) : src(_src), to(_to), cost(_cost) {} edge &operator=(const int &x) { to = x; return *this; } operator int() const { return to; } }; template using Edges = vector>; template using WeightedGraph = vector>; using UnweightedGraph = vector>; // Input of (Unweighted) Graph UnweightedGraph graph(int N, int M = -1, bool is_directed = false, bool is_1origin = true) { UnweightedGraph g(N); if (M == -1) M = N - 1; for (int _ = 0; _ < M; _++) { int x, y; cin >> x >> y; if (is_1origin) x--, y--; g[x].push_back(y); if (!is_directed) g[y].push_back(x); } return g; } // Input of Weighted Graph template WeightedGraph wgraph(int N, int M = -1, bool is_directed = false, bool is_1origin = true) { WeightedGraph g(N); if (M == -1) M = N - 1; for (int _ = 0; _ < M; _++) { int x, y; cin >> x >> y; T c; cin >> c; if (is_1origin) x--, y--; g[x].emplace_back(x, y, c); if (!is_directed) g[y].emplace_back(y, x, c); } return g; } // End include: "../graph/graph-template.hpp" template struct HeavyLightDecomposition { private: void dfs_sz(int cur) { size[cur] = 1; for (auto& dst : g[cur]) { if (dst == par[cur]) { if (g[cur].size() >= 2 && int(dst) == int(g[cur][0])) swap(g[cur][0], g[cur][1]); else continue; } depth[dst] = depth[cur] + 1; par[dst] = cur; dfs_sz(dst); size[cur] += size[dst]; if (size[dst] > size[g[cur][0]]) { swap(dst, g[cur][0]); } } } void dfs_hld(int cur) { down[cur] = id++; for (auto dst : g[cur]) { if (dst == par[cur]) continue; nxt[dst] = (int(dst) == int(g[cur][0]) ? nxt[cur] : int(dst)); dfs_hld(dst); } up[cur] = id; } // [u, v) 半開区間を閉区間に分解 vector> ascend(int u, int v) const { vector> res; while (nxt[u] != nxt[v]) { res.emplace_back(down[u], down[nxt[u]]); u = par[nxt[u]]; } if (u != v) res.emplace_back(down[u], down[v] + 1); return res; } vector> ascend_origin(int u, int v) const { vector> res; while (nxt[u] != nxt[v]) { res.emplace_back(u, nxt[u]); u = par[nxt[u]]; } if (u != v) res.emplace_back(u, g[v][0]); return res; } // (u, v] 半開区間を閉区間に分解 vector> descend(int u, int v) const { if (u == v) return {}; if (nxt[u] == nxt[v]) return {{down[u] + 1, down[v]}}; auto res = descend(u, par[nxt[v]]); res.emplace_back(down[nxt[v]], down[v]); return res; } vector> descend_origin(int u, int v) const { if (u == v) return {}; if (nxt[u] == nxt[v]) return {{g[u][0], v}}; auto res = descend_origin(u, par[nxt[v]]); res.emplace_back(nxt[v], v); return res; } public: G& g; int root, id; vector size, depth, down, up, nxt, par; HeavyLightDecomposition(G& _g, int _root = 0) : g(_g), root(_root), id(0), size(g.size(), 0), depth(g.size(), 0), down(g.size(), -1), up(g.size(), -1), nxt(g.size(), root), par(g.size(), root) { dfs_sz(root); dfs_hld(root); } pair idx(int i) const { return make_pair(down[i], up[i]); } template void path_query(int u, int v, bool vertex, const F& f) { int l = lca(u, v); for (auto&& [a, b] : ascend(u, l)) { int s = a + 1, t = b; s > t ? f(t, s) : f(s, t); } if (vertex) f(down[l], down[l] + 1); for (auto&& [a, b] : descend(l, v)) { int s = a, t = b + 1; s > t ? f(t, s) : f(s, t); } } template void path_noncommutative_query(int u, int v, bool vertex, const F& f) { int l = lca(u, v); for (auto&& [a, b] : ascend(u, l)) f(a + 1, b); if (vertex) f(down[l], down[l] + 1); for (auto&& [a, b] : descend(l, v)) f(a, b + 1); } // 閉区間 -> 閉区間たち vector> path_query_origin(int u, int v, bool vertex = 1) { int l = lca(u, v); auto ans = ascend_origin(u, l); if (vertex) ans.emplace_back(l, l); for (auto&& [a, b] : descend_origin(l, v)) ans.emplace_back(a, b); return ans; } template void subtree_query(int u, bool vertex, const F& f) { f(down[u] + int(!vertex), up[u]); } int lca(int a, int b) { while (nxt[a] != nxt[b]) { if (down[a] < down[b]) swap(a, b); a = par[nxt[a]]; } return depth[a] < depth[b] ? a : b; } int dist(int a, int b) { return depth[a] + depth[b] - depth[lca(a, b)] * 2; } }; /** * @brief Heavy Light Decomposition(重軽分解) * @docs docs/tree/heavy-light-decomposition.md */ // End include: "../tree/heavy-light-decomposition.hpp" // Begin include: "graph-template.hpp" // End include: "graph-template.hpp" using namespace std; template struct Namori { using G = WeightedGraph; int n; G g; // 部分グラフ vector aux; // ループ部分の(頂点,辺の重み) // loop[i].se は loop[i] と loop[i+1] の間の辺 vector> loop; // 頂点の対応関係 vector> mp; // HL分解 vector> hld; Namori(int _n = 0) : _uf(_n) { init(_n); } void init(int _n) { n = _n; g.resize(n); _uf.data.resize(n); fill(begin(_uf.data), end(_uf.data), -1); _is_loop.resize(n, false); mp.resize(n, make_pair(-1, -1)); } void add_edge(int u, int v, T w = 1) { assert(_built == false); if (_uf.same(u, v)) { _root = u, _adj = v, _w = w; } else { _uf.unite(u, v); g[u].emplace_back(u, v, w); g[v].emplace_back(v, u, w); } if (++_es == n) build(); } void build() { if (_built) return; _buf.resize(n, -1); dfs1(_root, -1); for (int c = _adj; c >= 0; c = _buf[c]) { loop.emplace_back(c, -1); _is_loop[c] = true; for (auto& e : g[c]) { if (e == _buf[c]) loop.back().second = e.cost; } } assert(loop.back().first == _root); loop.back().second = _w; _h.resize(n); for (auto& [i, _] : loop) dfs2(i, -1); fill(begin(_buf), end(_buf), 0); for (auto& [i, _] : loop) dfs3(i); _uf.data.clear(); _buf.clear(); _is_loop.clear(); aux.resize(loop.size()); for (int i = 0; i < (int)loop.size(); i++) { int k = loop[i].first, j = 0; dfs4(k, i, j); aux[i].resize(j); dfs5(k); hld.emplace_back(aux[i]); } _h.clear(); _built = true; } pair idx(int i) const { return mp[i]; } int root(int i) const { return loop[mp[i].first].first; } private: // 初期化用の状態変数 UnionFind _uf; vector _buf; vector _is_loop; int _root = -1, _adj = -1, _es = 0; bool _built = false; T _w = 0; G _h; // parをメモする void dfs1(int c, int p) { for (auto& d : g[c]) { if (d != p) { _buf[d] = c; dfs1(d, c); } } } // _h で有向木を作る void dfs2(int c, int p) { for (auto& d : g[c]) { if (d == p or _is_loop[d]) continue; _h[c].emplace_back(c, d, d.cost); dfs2(d, c); } } // HLD用に順番替え void dfs3(int c) { _buf[c] = 1; for (auto& d : _h[c]) { dfs3(d); _buf[c] += _buf[d]; if (_buf[d] > _buf[_h[c][0]]) { swap(_h[c][0], d); } } } // 順番をつける void dfs4(int c, int i, int& j) { mp[c] = make_pair(i, j++); for (auto& d : _h[c]) { dfs4(d, i, j); } } // 部分グラフを作る void dfs5(int c) { for (auto& d : _h[c]) { dfs5(d); auto [i, j] = mp[c]; auto [_, k] = mp[d]; aux[i][j].emplace_back(j, k, d.cost); // 逆辺も入れたいときはここをオンにする(動くか不明) // aux[i][k].emplace_back(k, j, d.cost); } } }; /** * @brief Functional Graph(なもりグラフ)の分解 * @docs docs/graph/functional-graph.md */ // End include: "../../graph/namori.hpp" // Begin include: "../../graph/undirected-namori.hpp" // Gは連結グラフである必要がある // 有向なもりを返す template Graph UndirectedNamori(Graph G) { int N = G.size(); int M = 0; Graph g(N); queue q; vector cnt(N); for (int i = 0; i < N; i++) { cnt[i] = G[i].size(); if (G[i].size() == 1) q.push(i); } vector decom(N); while(!q.empty()) { int pos = q.front(); q.pop(); for (auto& e : G[pos]) if (!decom[e]) { g[pos].emplace_back(e); ++M; if (--cnt[e] == 1) q.push(e); } decom[pos] = true; } auto dfs = [&](auto&& self, int pos, int par)->void{ if (M == N) return; for (auto& e: G[pos]) if (e != par && !decom[e]) { g[pos].emplace_back(e); ++M; if (M == N) return; self(self, e, pos); if (M == N) return; } }; for (int i = 0; i < N; i++) if (!decom[i]) { dfs(dfs, i, -1); break; } return g; } // End include: "../../graph/undirected-namori.hpp" // Begin include: "../../graph/graph-template.hpp" // End include: "../../graph/graph-template.hpp" using namespace yamada; ll cal_cyc(vl A,ll K){ ll N=A.size(); vl C(N); rep(i,N-1)C[i+1]=A[i]-C[i]; if(N%2){ ll d=A.back()-(C.front()+C.back()); if(d%2)return infLL; rep(i,0,N,2)C[i]+=d/2; rep(i,1,N,2)C[i]-=d/2; ll ans=0; rep(u,N){ if(0bool{ ll li=lb(A,l); ll ri=lb(A,r); return lill{ // 辺0の寄与がX if(exs(C0,-infLL,-X))return infLL; if(exs(C0,-X+1,-X+K))return infLL; if(exs(C1,-infLL,X))return infLL; if(exs(C1,-infLL,X+K))return infLL; ll xquo=Floor(X,K*2); ll xrem=Modulo(X,K*2); ll ans=ansbase; { ll m=ub(c0,K*2-xrem); ans+=m*xquo; ans+=(N/2-m)*(xquo+1); } { ll m=ub(c1,xrem); ans-=m*(xquo+1); ans-=(N/2-m)*xquo; } return ans; }; ll ans=infLL; each(c,C0)amin(ans,get(-c)); each(c,C1)amin(ans,get(c)); each(c,c0)amin(ans,get(-c)); each(c,c1)amin(ans,get(c)); return ans; } pr cal_tree(WeightedGraph g,vl A,ll K){ ll N=g.size(); auto cnt=A; // u,p(u) に施す回数 auto dfs=[&](auto&& self,ll u)->ll{ each(v,g[u])cnt[u]-=self(self,v); return cnt[u]; }; dfs(dfs,0); if(Min(cnt)<0)return {infLL,infLL}; rep(u,1,N)if(0 nam(N); rep(u,N)each(v,g[u])nam.add_edge(u,v); ll M=nam.aux.size(); vvl B(M); rep(gi,M)B[gi].resize(nam.aux[gi].size()); rep(u,N){ auto[i,j]=nam.idx(u); B[i][j]=A[u]; } ll ans=0; vl Acyc; rep(gi,M){ auto& t=nam.aux[gi]; ll n=t.size(); auto[bns,a]=cal_tree(t,B[gi],K); if(bns==infLL)die(-1); ans+=bns; Acyc.eb(a); } ll bns=cal_cyc(Acyc,K); if(bns==infLL)die(-1); out(ans+bns); }