#if ! defined(ONLINE_JUDGE) && __has_include("template.hpp") #include "template.hpp" #else // template start #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using ll = long long; using pall = pair; template using vec = vector; template using veve = vec>; using vell = vec; using vest = vec; using vebo = basic_string; using vevell = veve; template using mset = multiset; template using priority_queue_ascend = priority_queue, greater>; constexpr ll inf = numeric_limits::max() / 2; constexpr string sp{" "}; constexpr string lf{"\n"}; inline const auto &npos = string::npos; constexpr array grid_move4{{{0, 1}, {-1, 0}, {0, -1}, {1, 0}}}; constexpr array grid_move8{ {{0, 1}, {-1, 0}, {0, -1}, {1, 0}, {-1, 1}, {-1, -1}, {1, -1}, {1, 1}}}; #define cont continue #define ocnt cont #define br break #define whlie while #define whiel while #define foR for #define reutnr return #define retunr return #define reutrn return #define auot auto #define uato auto #define uaot auto #define atuo auto #define cosnt const #define conts const #define ocnst const inline auto &ciN = cin; inline auto &icn = cin; inline auto &icN = cin; constexpr bool ture = true; constexpr bool flase = false; namespace ra = ranges; using namespace atcoder; #define times(N) \ static_assert(is_integral_v>, \ "times(): N must be integral"); \ assert((N) >= 0); \ for(typedef remove_cvref_t _int; \ [[maybe_unused]] const _int ii : views::iota((_int)0, (N))) #define tiems times #define itmes times template istream &operator>>(istream &in, static_modint &i) { ll tmp; in >> tmp; i = tmp; return in; } template istream &operator>>(istream &in, dynamic_modint &i) { ll tmp; in >> tmp; i = tmp; return in; } template ostream &operator<<(ostream &out, const static_modint &i) { return out << i.val(); } template ostream &operator<<(ostream &out, const dynamic_modint &i) { return out << i.val(); } template istream &operator>>(istream &in, pair &p) { return in >> p.first >> p.second; } template ostream &operator<<(ostream &out, const pair &p) { return out << p.first << sp << p.second; } template istream &operator>>(istream &in, vec &v) { for(auto &e : v) { in >> e; } return in; } struct debug_stream { template debug_stream &operator<<([[maybe_unused]] const T &x) { #ifndef ONLINE_JUDGE clog << x; #endif return *this; } debug_stream &operator<<([[maybe_unused]] ostream &(*f)(ostream &)) { #ifndef ONLINE_JUDGE clog << f; #endif return *this; } }; template concept out_stream = same_as || same_as; inline debug_stream clog_; #define clog clog_ template istream &in(Ts &...vecs) { static_assert(sizeof...(vecs) != 0, "myfunc::in(): At least one vector must be provided"); const set sizes = {vecs.size()...}; if(sizes.size() > 1) { throw invalid_argument("myfunc::in(): All vectors must have the same size"); } times(*sizes.begin()) { ((cin >> vecs[ii]), ...); } return cin; } auto out(const ranges::range auto &v, const string delim, out_stream auto &out) -> add_lvalue_reference_t { for(auto &&e : v) { out << e << delim; } return out; } decltype(auto) out(const ranges::range auto &v, const string delim) { return out(v, delim, cout); } inline void yes() noexcept { cout << "Yes" << lf; } inline void no() noexcept { cout << "No" << lf; } inline void yesu() noexcept { cout << "YES" << lf; } inline void nou() noexcept { cout << "NO" << lf; } // [mi, ma) [[nodiscard]] inline uint64_t randint(const uint64_t mi, const uint64_t ma) noexcept { static mt19937_64 mt(random_device{}()); if(mi > ma) [[unlikely]] return randint(ma, mi); if(mi == ma) [[unlikely]] return mi; const uint64_t w = ma - mi; uint64_t r; do { r = mt(); } while(mt.max() - mt.max() % w <= r); return r % w + mi; } template requires common_with [[nodiscard]] constexpr auto min(T &&a, U &&b) noexcept { return std::min>(std::forward(a), std::forward(b)); } template requires common_with [[nodiscard]] constexpr auto max(T &&a, U &&b) noexcept { return std::max>(std::forward(a), std::forward(b)); } template [[nodiscard]] auto reduce(const ranges::range auto &r, Args &&...args) { return reduce(ranges::cbegin(r), ranges::cend(r), std::forward(args)...); } template auto popcnt(T &&x) { return popcount>(std::forward(x)); } [[nodiscard]] constexpr ll powll(ll a, ll b, const ll m = numeric_limits::max()) { if(b < 0) [[unlikely]] throw invalid_argument("powll(): exponent less than zero"); if(m < 1) [[unlikely]] throw invalid_argument("powll(): modulo less than one"); a %= m; ll ret = 1; while(b) { if(b % 2) ret *= a, ret %= m; a *= a, a %= m; b /= 2; } return ret; } template requires assignable_from && totally_ordered_with bool mini(T &var, U &&val) noexcept { const bool cmp = var > val; if(cmp) var = val; return cmp; } template requires assignable_from && totally_ordered_with bool maxi(T &var, U &&val) noexcept { const bool cmp = var < val; if(cmp) var = val; return cmp; } template class Map, class K, class V> requires same_as, map> || same_as, unordered_map> [[nodiscard]] V vmin(const Map &m) noexcept { if(m.empty()) { assert(is_default_constructible_v); return V{}; } V mi = m.begin()->second; for(const auto &[_, val] : m) { mini(mi, val); } return mi; } template class Map, class K, class V> requires same_as, map> || same_as, unordered_map> [[nodiscard]] V vmax(const Map &m) noexcept { if(m.empty()) { assert(is_default_constructible_v); return V{}; } V ma = m.begin()->second; for(const auto &[_, val] : m) { maxi(ma, val); } return ma; } class [[nodiscard]] grid_base { public: grid_base(const ll h, const ll w) noexcept : height(h), width(w) {} [[nodiscard]] ll operator()(const ll i, const ll j) const noexcept { if(! isvalid(i, j)) return -1; return i * width + j; } [[nodiscard]] ll operator()(const pall &p) const noexcept { return (*this)(p.first, p.second); } protected: bool isvalid(const ll i, const ll j) const noexcept { return 0 <= i && 0 <= j && i < height && j < width; } const ll height, width; }; class [[nodiscard]] grid_seen : public grid_base { public: grid_seen(const ll h, const ll w) : grid_base(h, w) { visited = vebo(h * w, false); } [[nodiscard]] bool &seen(const ll i, const ll j) & { if(! isvalid(i, j)) [[unlikely]] throw out_of_range("grid_seen::seen(): out of range"); return visited[i * width + j]; } [[nodiscard]] bool &sen(const ll i, const ll j) & { return seen(i, j); } [[nodiscard]] bool &seen(const pall &p) & { return seen(p.first, p.second); } [[nodiscard]] bool &sen(const pall &p) & { return seen(p); } private: vebo visited; }; using grid = grid_base; template requires convertible_to::mapped_type> class default_map : public map { using Map = map; template static constexpr bool comparable = requires(Map::key_compare c, Map::key_type t, U u) { c(t, u); c(u, t); }; public: #ifdef __cpp_lib_associative_heterogeneous_insertion template U> requires comparable Map::mapped_type &operator[](const U &key) { Map::try_emplace(key, defval); return Map::operator[](key); } template U> requires comparable Map::mapped_type &operator[](const U &&key) { Map::try_emplace(key, defval); return Map::operator[](key); } #else Map::mapped_type &operator[](const Map::key_type &key) { Map::try_emplace(key, defval); return Map::operator[](key); } Map::mapped_type &operator[](const Map::key_type &&key) { Map::try_emplace(key, defval); return Map::operator[](key); } #endif }; template requires is_convertible_v::mapped_type> class default_unordered_map : public unordered_map { using Map = unordered_map; template static constexpr bool hashable = requires(Map::hasher h, U u) { h(u); }; public: #ifdef __cpp_lib_associative_heterogeneous_insertion template requires hashable Map::mapped_type &operator[](const U &key) { Map::try_emplace(key, defval); return Map::operator[](key); } template requires hashable Map::mapped_type &operator[](const U &&key) { Map::try_emplace(key, defval); return Map::operator[](key); } #else Map::mapped_type &operator[](const Map::key_type &key) { Map::try_emplace(key, defval); return Map::operator[](key); } Map::mapped_type &operator[](const Map::key_type &&key) { Map::try_emplace(key, defval); return Map::operator[](key); } #endif }; template requires requires(mset::key_compare c, T t, U u) { c(t, u); } auto erase_single(mset &mset, U &&v) { const auto it = mset.find(v); if(it == mset.end()) [[unlikely]] throw invalid_argument("erase_single(): why v not in mset!?!?"); return mset.erase(it); } // template end #endif #define MOD_IS_998 1 #ifdef MOD_IS_998 constexpr ll MOD = 998244353; #else constexpr ll MOD = 1e9 + 7; #endif using mint = static_modint; void init(); void solve(); int main(void) { cin.tie(nullptr); ios::sync_with_stdio(false); init(); ll t = 1; // cin >> t; times(t) solve(); return 0; } #include #include #include #include #include #include #include #include #include #include #include #include #include "atcoder/segtree.hpp" // yosupo library checker verified. // LCA https://judge.yosupo.jp/submission/319753 using namespace std; using namespace atcoder; using ll = long long; template struct is_map_like : std::false_type {}; template struct is_map_like> : std::true_type {}; template struct is_map_like> : std::true_type {}; template concept map_like = is_map_like>::value; template::mapped_type::mapped_type>> concept network = map_like && map_like::mapped_type> && integral::key_type> && integral::mapped_type::key_type> && same_as< remove_cvref_t::mapped_type::mapped_type>, T>; #define check_bound(var, lower, upper) \ assert(lower <= var); \ assert(var <= upper); template requires network class euler_tour { public: const ll root; const ll n; const G &nei; vector in, out, parent; vector edge_tour, depth; vector seen; euler_tour(const G &_nei, const ll _root) : root(_root), n([&] { ll ma = _root; for(const auto &[e, _] : _nei) { ma = max(ma, e); } return ma + 1; }()), nei(_nei) { init(); } private: void init() { edge_tour.reserve(2 * n); depth.reserve(2 * n - 1); in = vector(n); out = vector(n); parent = vector(n); seen = vector(n, false); dfs(root, 0); } void dfs(const ll i, const ll d) { seen[i] = true; depth.push_back(d); in[i] = edge_tour.size(); edge_tour.push_back(i); for(const auto &[e, _] : nei.at(i)) { if(seen[e]) continue; parent[e] = i; dfs(e, d + 1); depth.push_back(d); } out[i] = edge_tour.size(); edge_tour.push_back(-i); } }; template requires network && requires(T a, T b) { { e_op(a, b) } -> same_as; { el() } -> same_as; { inv(a) } -> same_as; } class et_static : public euler_tour { class range_minidx { public: range_minidx(vector &&_v) : n(_v.size()), lb_n(bit_width(n)), v(std::move(_v)) { tab = vector(lb_n, vector(n)); iota(tab[0].begin(), tab[0].end(), 0); for(size_t j = 1; j < lb_n; j++) { for(size_t i = 0; i + (1LL << (j - 1)) < n; i++) { const ll i1 = tab[j - 1][i]; const ll i2 = tab[j - 1][i + (1LL << (j - 1))]; tab[j][i] = v[i1] > v[i2] ? i2 : i1; } } } // [L, R) ll query(const ll l, const ll r) const { assert(0 <= l); assert(l < r); assert(r <= (ll)n); const size_t lb_w = bit_width(r - l) - 1; const ll i1 = tab[lb_w][l]; const ll i2 = tab[lb_w][r - (1LL << lb_w)]; return v[i1] > v[i2] ? i2 : i1; } private: const size_t n; const size_t lb_n; vector v; vector> tab; }; public: et_static(const G &nei, const ll _root = 0) : euler_tour(nei, _root), depth_t(std::move(this->depth)) { init(); } ll lca(const ll x, const ll y) const { check_bound(x, 0, this->n - 1); check_bound(y, 0, this->n - 1); const auto [l, r] = minmax(this->in[x], this->in[y]); const ll idx = this->depth_t.query(l, r + 1); ll ret = this->edge_tour[idx]; if(ret < 0) { ret = this->parent[-ret]; } return ret; } T path(const ll x, const ll y) const { check_bound(x, 0, this->n - 1); check_bound(y, 0, this->n - 1); const ll xidx = this->in[x]; const ll yidx = this->in[y]; const ll lca_idx = this->in[lca(x, y)]; const T x2lca = e_op(edge_val_r[xidx], inv(edge_val_r[lca_idx])); const T lca2y = e_op(inv(edge_val_l[lca_idx]), edge_val_l[yidx]); return e_op(x2lca, lca2y); } T subtree(const ll x) const { check_bound(x, 0, this->n - 1); const ll l = this->in[x]; const ll r = this->out[x]; return e_op(inv(edge_val_noinv[l]), edge_val_noinv[r]); } private: void init() { edge_val_l.reserve(2 * this->n); edge_val_r.reserve(2 * this->n); edge_val_noinv.reserve(2 * this->n); for(const auto &e : this->edge_tour) { if(abs(e) == this->root) { edge_val_l.push_back(el()); edge_val_r.push_back(el()); edge_val_noinv.push_back(el()); continue; } T val = this->nei.at(abs(e)).at(this->parent[abs(e)]); if(e < 0) val = inv(val); edge_val_l.push_back(e_op(edge_val_l.back(), val)); edge_val_r.push_back(e_op(val, edge_val_r.back())); edge_val_noinv.push_back(0 <= e ? e_op(edge_val_noinv.back(), val) : edge_val_noinv.back()); } } range_minidx depth_t; vector edge_val_l, edge_val_r, edge_val_noinv; }; template requires network && requires(T a, T b) { { e_op(a, b) } -> same_as; { el() } -> same_as; { inv(a) } -> same_as; } class et_dynamic : public euler_tour { using range_min = segtree; public: et_dynamic(const G &nei, const ll _root = 0) : euler_tour(nei, _root) { init(); } ll lca(const ll x, const ll y) const { check_bound(x, 0, this->n - 1); check_bound(y, 0, this->n - 1); const auto [l, r] = minmax(this->in[x], this->in[y]); const ll mi = depth_t.prod(l, r + 1); const ll idx = depth_t.max_right(l, [&mi](ll x) { return mi < x; }); ll ret = this->edge_tour[idx]; if(ret < 0) { ret = this->parent[-ret]; } return ret; } T path(const ll x, const ll y) const { check_bound(x, 0, this->n - 1); check_bound(y, 0, this->n - 1); const ll xidx = this->in[x]; const ll yidx = this->in[y]; const ll lca_idx = this->in[lca(x, y)]; const T x2lca = t_rev.prod(lca_idx + 1, xidx + 1); const T lca2y = t.prod(lca_idx + 1, yidx + 1); return e_op(x2lca, lca2y); } T subtree(const ll x) const { check_bound(x, 0, this->n - 1); const ll l = this->in[x] + 1; const ll r = this->out[x]; return t_noinv.prod(l, r); } void set(ll u, ll v, const T &val) { check_bound(u, 0, this->n - 1); check_bound(v, 0, this->n - 1); assert(this->nei.contains(u) && this->nei.at(u).contains(v)); if(this->depth[u] > this->depth[v]) swap(u, v); t.set(this->in[v], val); t_rev.set(this->in[v], val); t.set(this->out[v], inv(val)); t_rev.set(this->out[v], inv(val)); t_noinv.set(this->in[v], val); } private: void init() { depth_t = range_min(this->depth); vector v(this->edge_tour.size(), el()); vector v_noinv(this->edge_tour.size(), el()); for(size_t i = 0; i < this->edge_tour.size(); i++) { const auto &e = this->edge_tour[i]; if(abs(e) == this->root) continue; const T &val = this->nei.at(abs(e)).at(this->parent[abs(e)]); if(e < 0) { v[i] = inv(val); } else { v[i] = val; v_noinv[i] = val; } } t = decltype(t)(v); t_rev = decltype(t_rev)(v); t_noinv = decltype(t_noinv)(v_noinv); } range_min depth_t; segtree t, t_noinv; segtree t_rev; }; #undef check_bound void init() {} void solve() { ll n, m; cin >> n >> m; map> nei; times(n - 1) { ll u, v; cin >> u >> v; u--, v--; nei[u][v] = nei[v][u] = ii; } vevell mi(n, vell(n, inf)); vell par(n); const auto dfs = [&](auot &&self, const ll i) -> void { static vebo sen(n, false); sen[i] = ture; for(ocnst uaot &[ e, _ ] : nei[i]) { if(sen[e]) cont; par[e] = i; self(self, e); } }; dfs(dfs, 0); for(intmax_t i = 0; i < intmax_t(n); i++) { ll cur = i; ll v = inf; while(cur != 0) { const ll ev = nei[cur][par[cur]]; mini(v, ev); mi[i][par[cur]] = v; cur = par[cur]; } } vell tab(n - 1); tab[0] = m; et_static et(nei); itmes(m) { ll s, t; cin >> s >> t; s--, t--; const ll lca = et.lca(s, t); clog << lca << sp << mi[s][lca] << sp << mi[t][lca] << lf; tab[min(mi[s][lca], mi[t][lca])]--; } clog << lf; for(intmax_t i = 1; i < intmax_t(tab.size()); i++) { tab[i] += tab[i - 1]; } out(tab, lf); }