Problem p02728 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
#define WHOLE(v) (v).begin(), (v).end()
#define REV_WHOLE(v) (v).rbegin(), (v).rend()
using i64 = int64_t;
using namespace std;
template <class F> auto recursive(F f) {
  return [f](auto... a) { return f(f, a...); };
}
template <class I, class V = typename I::value_type>
V sum_up(const I &l, const I &r) {
  V v;
  for (I i = l; i != r; i++)
    v = i == l ? *i : v + *i;
  return v;
}
template <class I, class T = iterator_traits<I>> I operator+(I it, int n) {
  for (int i = 0; i < n; i++)
    it++;
  return it;
}
template <class I, class T = iterator_traits<I>> I operator-(I it, int n) {
  for (int i = 0; i < n; i++)
    it--;
  return it;
}
template <class T>
using rev_priority_queue = priority_queue<T, vector<T>, greater<T>>;
template <class T> using vector2d = vector<vector<T>>;
struct fixprec {
  int x;
  fixprec(int d) : x(d) {}
};
ostream &operator<<(ostream &o, fixprec f) {
  return o << fixed << setprecision(f.x);
}
void R_YESNO(bool p) { cout << (p ? "YES" : "NO") << endl; }
void R_YesNo(bool p) { cout << (p ? "Yes" : "No") << endl; }

/*!* [modint] *!*/
/*+* 剰余環整数と剰余階乗 *+*/
struct int_m;
int_m invmod(int_m);
int_m powmod(int_m, i64);
struct int_m {
  static i64 m;
  i64 v;
  int_m() {}
  int_m(i64 x) : v(x) {}
  int_m operator+(const int_m &y) const { return (v + y.v) % m; }
  int_m operator-(const int_m &y) const { return (v - y.v + m) % m; }
  int_m operator*(const int_m &y) const { return (v * y.v) % m; }
  int_m operator/(const int_m &y) const { return *this * invmod(y); }
  int_m operator^(const i64 &y) const { return powmod(*this, y); }
  void operator+=(const int_m &y) { *this = *this + y; }
  void operator-=(const int_m &y) { *this = *this - y; }
  void operator*=(const int_m &y) { *this = *this * y; }
  void operator/=(const int_m &y) { *this = *this / y; }
  void operator^=(const i64 &y) { *this = *this ^ y; }
  bool operator==(const int_m &y) const { return v == y.v; }
  bool operator!=(const int_m &y) const { return v != y.v; }
  friend istream &operator>>(istream &ist, int_m m) {
    ist >> m.v;
    return ist;
  }
  friend ostream &operator<<(ostream &ost, int_m m) {
    ost << m.v;
    return ost;
  }
};
i64 int_m::m;
// O(log a)
int_m powmod(int_m a, i64 p) {
  int_m v = 1;
  for (int_m b = a; p > 0; p >>= 1, b *= b)
    if (p & 1)
      v *= b;
  return v;
}
int_m invmod(int_m x) { return powmod(x, x.m - 2); }
struct ModFact {
  static vector<int_m> val, inv;
  static void Init(int N) { // O(N)
    val = vector<int_m>(++N, 1), inv = vector<int_m>(N, 1);
    for (int i = 1; i < N; i++)
      val[i] = val[i - 1] * i;
    inv[N - 1] = invmod(val[N - 1]);
    for (int i = N - 1; i > 0; i--)
      inv[i - 1] = inv[i] * i;
  }
};
vector<int_m> ModFact::val, ModFact::inv;
int_m Permutation(int n, int m) {
  if (n < m || m < 0 || n < 0)
    return 0;
  return ModFact::val[n] * ModFact::inv[n - m];
}
int_m Combination(int n, int m) {
  if (n < m || m < 0 || n < 0)
    return 0;
  return ModFact::val[n] * ModFact::inv[m] * ModFact::inv[n - m];
}
int_m Combination(vector<int> &n) {
  int s = accumulate(n.begin(), n.end(), 0);
  int_m r = ModFact::val[s];
  for (auto x : n)
    r *= ModFact::inv[x];
  return r;
}
int_m Multichoose(int n, int m) { return Combination(n + m - 1, m); }

using Data = tuple<int, int_m, bool>;
using Key = pair<int, int>;
using Value = pair<int, int_m>;

int main() {
  int_m::m = 1e9 + 7;
  ModFact::Init(5e5);
  int N;
  cin >> N;
  vector2d<int> e(N);
  for (int i = 0; i < N - 1; i++) {
    int a, b;
    cin >> a >> b;
    a--, b--;
    e[a].push_back(b);
    e[b].push_back(a);
  }

  // (i, j) |-> (n, x) : i を親とした j の部分木の頂点数が n で選び方が x
  map<Key, Value> dp;

  // 次数の大きいやつから計算して逆算高速化の効果を上げる
  priority_queue<Key> q;
  for (int i = 0; i < N; i++) {
    q.push({e[i].size(), i});
  }

  vector<int_m> ans_v(N);

  while (q.size()) {
    int dummy, v;
    int_m ans;
    tie(dummy, v) = q.top();
    q.pop();
    tie(dummy, ans) = recursive([&](auto f, int i, int j) -> Value {
      if (!dp.count({i, j})) {
        vector<int> c;
        int n = 1;   // 自分だけ
        int_m x = 1; // 空積
        // 逆算で求められる場合は高速化
        if (dp.count({-1, j}) && dp.count({j, i})) {
          int n_small = dp[{j, i}].first;
          n = N - n_small;
          int_m x_big = dp[{-1, j}].second;
          int_m x_small = dp[{j, i}].second;
          // N - 1 は頂点j以外のすべての頂点数
          x = (x_big / x_small) / Combination(N - 1, n_small);
        } else {
          for (int k : e[j]) {
            if (k == i)
              continue;
            int n_k;   // 頂点k配下の(自分も含む)頂点の数
            int_m x_k; // 頂点k配下の部分木の選び方の数
            tie(n_k, x_k) = f(f, j, k);
            c.push_back(n_k);
            n += n_k;
            x *= x_k;
          }
          if (c.size()) { // どの部分木から取るかの選び方
            x *= Combination(c);
          }
        }
        dp[{i, j}] = {n, x};
      }
      return dp[{i, j}];
    })(-1, v);
    ans_v[v] = ans;
  }
  for (int_m x : ans_v)
    cout << x << endl;
  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
#define WHOLE(v) (v).begin(), (v).end()
#define REV_WHOLE(v) (v).rbegin(), (v).rend()
using i64 = int64_t;
using namespace std;
template <class F> auto recursive(F f) {
  return [f](auto... a) { return f(f, a...); };
}
template <class I, class V = typename I::value_type>
V sum_up(const I &l, const I &r) {
  V v;
  for (I i = l; i != r; i++)
    v = i == l ? *i : v + *i;
  return v;
}
template <class I, class T = iterator_traits<I>> I operator+(I it, int n) {
  for (int i = 0; i < n; i++)
    it++;
  return it;
}
template <class I, class T = iterator_traits<I>> I operator-(I it, int n) {
  for (int i = 0; i < n; i++)
    it--;
  return it;
}
template <class T>
using rev_priority_queue = priority_queue<T, vector<T>, greater<T>>;
template <class T> using vector2d = vector<vector<T>>;
struct fixprec {
  int x;
  fixprec(int d) : x(d) {}
};
ostream &operator<<(ostream &o, fixprec f) {
  return o << fixed << setprecision(f.x);
}
void R_YESNO(bool p) { cout << (p ? "YES" : "NO") << endl; }
void R_YesNo(bool p) { cout << (p ? "Yes" : "No") << endl; }

/*!* [modint] *!*/
/*+* 剰余環整数と剰余階乗 *+*/
struct int_m;
int_m invmod(int_m);
int_m powmod(int_m, i64);
struct int_m {
  static i64 m;
  i64 v;
  int_m() {}
  int_m(i64 x) : v(x) {}
  int_m operator+(const int_m &y) const { return (v + y.v) % m; }
  int_m operator-(const int_m &y) const { return (v - y.v + m) % m; }
  int_m operator*(const int_m &y) const { return (v * y.v) % m; }
  int_m operator/(const int_m &y) const { return *this * invmod(y); }
  int_m operator^(const i64 &y) const { return powmod(*this, y); }
  void operator+=(const int_m &y) { *this = *this + y; }
  void operator-=(const int_m &y) { *this = *this - y; }
  void operator*=(const int_m &y) { *this = *this * y; }
  void operator/=(const int_m &y) { *this = *this / y; }
  void operator^=(const i64 &y) { *this = *this ^ y; }
  bool operator==(const int_m &y) const { return v == y.v; }
  bool operator!=(const int_m &y) const { return v != y.v; }
  friend istream &operator>>(istream &ist, int_m m) {
    ist >> m.v;
    return ist;
  }
  friend ostream &operator<<(ostream &ost, int_m m) {
    ost << m.v;
    return ost;
  }
};
i64 int_m::m;
// O(log a)
int_m powmod(int_m a, i64 p) {
  int_m v = 1;
  for (int_m b = a; p > 0; p >>= 1, b *= b)
    if (p & 1)
      v *= b;
  return v;
}
int_m invmod(int_m x) { return powmod(x, x.m - 2); }
struct ModFact {
  static vector<int_m> val, inv;
  static void Init(int N) { // O(N)
    val = vector<int_m>(++N, 1), inv = vector<int_m>(N, 1);
    for (int i = 1; i < N; i++)
      val[i] = val[i - 1] * i;
    inv[N - 1] = invmod(val[N - 1]);
    for (int i = N - 1; i > 0; i--)
      inv[i - 1] = inv[i] * i;
  }
};
vector<int_m> ModFact::val, ModFact::inv;
int_m Permutation(int n, int m) {
  if (n < m || m < 0 || n < 0)
    return 0;
  return ModFact::val[n] * ModFact::inv[n - m];
}
int_m Combination(int n, int m) {
  if (n < m || m < 0 || n < 0)
    return 0;
  return ModFact::val[n] * ModFact::inv[m] * ModFact::inv[n - m];
}
int_m Combination(vector<int> &n) {
  int s = accumulate(n.begin(), n.end(), 0);
  int_m r = ModFact::val[s];
  for (auto x : n)
    r *= ModFact::inv[x];
  return r;
}
int_m Multichoose(int n, int m) { return Combination(n + m - 1, m); }

using Data = tuple<int, int_m, bool>;
using Key = pair<int, int>;
using Value = pair<int, int_m>;

int main() {
  int_m::m = 1e9 + 7;
  ModFact::Init(5e5);
  int N;
  cin >> N;
  vector2d<int> e(N);
  for (int i = 0; i < N - 1; i++) {
    int a, b;
    cin >> a >> b;
    a--, b--;
    e[a].push_back(b);
    e[b].push_back(a);
  }

  // (j, i) |-> (n, x) : i を親とした j の部分木の頂点数が n で選び方が x
  vector<map<int, Value>> dp(N);

  for (int v = 0; v < N; v++) {
    int dummy;
    int_m ans;
    tie(dummy, ans) = recursive([&](auto f, int i, int j) -> Value {
      if (!dp[j].count(i)) {
        vector<int> c;
        int n = 1; // 自分だけ
        int_m x = 1;
        // 引き算で求められる場合は高速化
        if (dp[j].count(-1) && dp[i].count(j)) {
          int n_small = dp[i][j].first;
          n = N - n_small;
          int_m x_big = dp[j][-1].second;
          int_m x_small = dp[i][j].second;
          // N - 1 は頂点j以外のすべての頂点数
          x = (x_big / x_small) / Combination(N - 1, n_small);
        } else {
          for (int k : e[j]) {
            if (k == i)
              continue;
            int n_k;   // 頂点k配下の(自分も含む)頂点の数
            int_m x_k; // 頂点k配下の部分木の選び方の数
            tie(n_k, x_k) = f(f, j, k);
            c.push_back(n_k);
            n += n_k;
            x *= x_k;
          }
          if (c.size()) { // どの部分木から取るかの選び方
            x *= Combination(c);
          }
        }
        dp[j][i] = {n, x};
      }
      return dp[j][i];
    })(-1, v);
    cout << ans << endl;
  }
  return 0;
}