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

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr ll MOD = 1e9 + 7;

template <long long P> long long modinv(long long n) {
  long long a = P, u = 1, v = 0;
  while (a) {
    long long t = n / a;
    n -= t * a;
    std::swap(n, a);
    u -= t * v;
    std::swap(u, v);
  }
  u %= P;
  if (u < 0)
    u += P;
  return u;
}

template <long long M> struct modint {
  long long val;

  modint<M>(long long right) : val(right) { sub(val); }
  modint<M>() { val = 0; }

  void sub(long long &n) {
    if (n < 0) {
      long long m = (-n) % M;
      n = M - m;
    } else
      n %= M;
  }

  modint<M> operator+(modint<M> right) { return (this->val) + right.val; }
  modint<M> operator+(long long right) {
    sub(right);
    return (this->val) + right;
  }
  modint<M> operator-(modint<M> right) { return (this->val) - right.val; }
  modint<M> operator-(long long right) {
    sub(right);
    return (this->val) - right;
  }
  modint<M> operator*(modint<M> right) { return (this->val) * right.val; }
  modint<M> operator*(long long right) {
    sub(right);
    return (this->val) * right;
  }

  void operator+=(modint<M> right) { *this = *this + right; }
  void operator+=(long long right) { *this = *this + right; }
  void operator-=(modint<M> right) { *this = *this - right; }
  void operator-=(long long right) { *this = *this - right; }
  void operator*=(modint<M> right) { *this = *this * right; }
  void operator*=(long long right) { *this = *this * right; }

  modint<M> &operator++() {
    *this += 1;
    return *this;
  }
  modint<M> operator++(int) {
    *this += 1;
    return *this - 1;
  }
  modint<M> &operator--() {
    *this -= 1;
    return *this;
  }
  modint<M> operator--(int) {
    *this -= 1;
    return *this + 1;
  }

  modint<M> operator/(modint<M> right) { return *this * modinv<M>(right.val); }
  modint<M> operator/(long long right) {
    sub(right);
    return *this * modinv<M>(right);
  }

  void operator/=(modint<M> right) { *this = *this / right; }
  void operator/=(long long right) { *this = *this / right; }
};

std::vector<long long> factorial;
std::vector<long long> factorial_inv;

template <long long P> void make_table(long long n) {
  factorial.resize(n + 1, 1);
  factorial_inv.resize(n + 1, 1);
  for (long long i = 2; i <= n; i++) {
    factorial[i] = factorial[i - 1] * i % P;
  }
  factorial_inv[n] = modinv<P>(factorial[n]);
  for (long long i = n - 1; i >= 0; i--) {
    factorial_inv[i] = factorial_inv[i + 1] * (i + 1) % P;
  }
}

template <long long P> modint<P> permutation(long long n, long long r) {
  if (n <= factorial.size()) {
    modint<P> a = factorial[n], b = factorial_inv[n - r];
    return a * b;
  } else {
    std::cerr << "attention : factorial table is not constructed\\n";
    modint<P> ret = 1;
    for (long long i = 0; i < r; i++)
      ret *= n - i;
    return ret;
  }
}

template <long long P> modint<P> combination(long long n, long long r) {
  r = std::min(r, n - r);
  if (n <= factorial.size()) {
    return permutation<P>(n, r) * factorial_inv[r];
  } else {
    std::cerr << "attention : factorial table is not constructed\\n";
    modint<P> ret = 1;
    for (long long i = 0; i < r; i++) {
      ret *= n - i;
      ret /= i + 1;
    }
    return ret;
  }
}

template <long long M>
std::ostream &operator<<(std::ostream &out, modint<M> tgt) {
  out << tgt.val;
  return out;
}

struct rerooting {
  struct DP {
    long long cnt;
    modint<MOD> dp;
    DP operator+(DP right) {
      DP ret = *this;
      ret.cnt += right.cnt;
      ret.dp *= right.dp;
      ret.dp *= combination<MOD>(ret.cnt, right.cnt);
      return ret;
    }
    DP ascend(long long prev, long long now, long long idx) {
      cnt++;
      return {cnt, dp};
    }
  };
  struct rr_edge {
    long long from;
    long long to;
    long long weight;
    long long reverse_idx; // 逆向きの辺の adj_list における第2引数
  };

  long long n;
  std::vector<std::vector<rr_edge>> adj_list;
  std::vector<std::vector<DP>> subans;
  std::vector<std::vector<DP>> left_sum;
  std::vector<std::vector<DP>> right_sum;
  std::vector<DP> ans;
  DP id_e = {0, 1}; // edit here

  rerooting(long long n) : n(n) {
    adj_list.resize(n);
    subans.resize(n);
    left_sum.resize(n);
    right_sum.resize(n);
    ans.resize(n, id_e);
  }

  void make_egde(long long s, long long t, long long w = 1) {
    adj_list[s].push_back({s, t, w, (long long)adj_list[t].size()});
    adj_list[t].push_back({t, s, w, (long long)adj_list[s].size() - 1});
    subans[s].push_back(id_e);
    subans[t].push_back(id_e);
  }

  void calculate() {
    ans[0] = dfs1(-1, 0, -1);
    make_sum(0);
    dfs2(-1, 0, -1);
  }

  void make_sum(long long now) {
    long long m = adj_list[now].size();
    left_sum[now].resize(m + 1, id_e);
    right_sum[now].resize(m + 1, id_e);
    for (long long i = 0; i < m; i++) {
      left_sum[now][i + 1] = left_sum[now][i] + subans[now][i];
    }
    for (long long i = m - 1; i >= 0; i--) {
      right_sum[now][i] = right_sum[now][i + 1] + subans[now][i];
    }
  }

  DP dfs1(long long prev, long long now, long long idx) {
    DP ret = id_e;
    for (long long i = 0; i < adj_list[now].size(); i++) {
      if (adj_list[now][i].to == prev)
        continue;
      subans[now][i] = dfs1(now, adj_list[now][i].to, i);
      ret = ret + subans[now][i];
    }
    return ret.ascend(prev, now, idx);
  }

  void dfs2(long long prev, long long now, long long idx) {
    if (now > 0) {
      DP x = left_sum[prev][idx] + right_sum[prev][idx + 1];
      subans[now][adj_list[prev][idx].reverse_idx] =
          x.ascend(now, prev, adj_list[prev][idx].reverse_idx);
      make_sum(now);
      ans[now] = left_sum[now].back().ascend(-1, now, -1);
    }
    for (long long i = 0; i < adj_list[now].size(); i++) {
      if (adj_list[now][i].to == prev)
        continue;
      dfs2(now, adj_list[now][i].to, i);
    }
  }
};

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

  ll n;
  cin >> n;
  make_table<MOD>(2e5);
  rerooting rr(n);
  for (ll i = 0; i < n - 1; i++) {
    ll a, b;
    cin >> a >> b;
    rr.make_egde(a - 1, b - 1);
  }
  rr.calculate();
  for (auto i : rr.ans)
    cout << i.dp << '\\n';
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr ll MOD = 1e9 + 7;

template <long long P> long long modinv(long long n) {
  long long a = P, u = 1, v = 0;
  while (a) {
    long long t = n / a;
    n -= t * a;
    std::swap(n, a);
    u -= t * v;
    std::swap(u, v);
  }
  u %= P;
  if (u < 0)
    u += P;
  return u;
}

template <long long M> struct modint {
  long long val;

  modint<M>(long long right) : val(right) { sub(val); }
  modint<M>() { val = 0; }

  void sub(long long &n) {
    if (n < 0) {
      long long m = (-n) % M;
      n = M - m;
    } else
      n %= M;
  }

  modint<M> operator+(modint<M> right) { return (this->val) + right.val; }
  modint<M> operator+(long long right) {
    sub(right);
    return (this->val) + right;
  }
  modint<M> operator-(modint<M> right) { return (this->val) - right.val; }
  modint<M> operator-(long long right) {
    sub(right);
    return (this->val) - right;
  }
  modint<M> operator*(modint<M> right) { return (this->val) * right.val; }
  modint<M> operator*(long long right) {
    sub(right);
    return (this->val) * right;
  }

  void operator+=(modint<M> right) { *this = *this + right; }
  void operator+=(long long right) { *this = *this + right; }
  void operator-=(modint<M> right) { *this = *this - right; }
  void operator-=(long long right) { *this = *this - right; }
  void operator*=(modint<M> right) { *this = *this * right; }
  void operator*=(long long right) { *this = *this * right; }

  modint<M> &operator++() {
    *this += 1;
    return *this;
  }
  modint<M> operator++(int) {
    *this += 1;
    return *this - 1;
  }
  modint<M> &operator--() {
    *this -= 1;
    return *this;
  }
  modint<M> operator--(int) {
    *this -= 1;
    return *this + 1;
  }

  modint<M> operator/(modint<M> right) { return *this * modinv<M>(right.val); }
  modint<M> operator/(long long right) {
    sub(right);
    return *this * modinv<M>(right);
  }

  void operator/=(modint<M> right) { *this = *this / right; }
  void operator/=(long long right) { *this = *this / right; }
};

std::vector<long long> factorial;
std::vector<long long> factorial_inv;

template <long long P> void make_table(long long n) {
  factorial.resize(n + 1, 1);
  factorial_inv.resize(n + 1, 1);
  for (long long i = 2; i <= n; i++) {
    factorial[i] = factorial[i - 1] * i % P;
  }
  factorial_inv[n] = modinv<P>(factorial[n]);
  for (long long i = n - 1; i >= 0; i--) {
    factorial_inv[i] = factorial_inv[i + 1] * (i + 1) % P;
  }
}

template <long long P> modint<P> permutation(long long n, long long r) {
  if (n <= factorial.size()) {
    modint<P> a = factorial[n], b = factorial_inv[n - r];
    return a * b;
  } else {
    std::cerr << "attention : factorial table is not constructed\\n";
    modint<P> ret = 1;
    for (long long i = 0; i < r; i++)
      ret *= n - i;
    return ret;
  }
}

template <long long P> modint<P> combination(long long n, long long r) {
  r = std::min(r, n - r);
  if (n <= factorial.size()) {
    return permutation<P>(n, r) * factorial_inv[r];
  } else {
    std::cerr << "attention : factorial table is not constructed\\n";
    modint<P> ret = 1;
    for (long long i = 0; i < r; i++) {
      ret *= n - i;
      ret /= i + 1;
    }
    return ret;
  }
}

template <long long M>
std::ostream &operator<<(std::ostream &out, modint<M> tgt) {
  out << tgt.val;
  return out;
}

template <typename T> struct rerooting {
  struct rr_edge {
    long long from;
    long long to;
    long long weight;
    T dp;
    long long reverse_idx; // 逆向きの辺の adj_list における第2引数
  };

  long long n;
  std::vector<std::vector<rr_edge>> adj_list;
  std::vector<std::vector<T>> left_sum;
  std::vector<std::vector<T>> right_sum;
  std::vector<T> dp;
  T id_e = {0, 1}; // edit here

  rerooting(long long n) : n(n) {
    adj_list.resize(n);
    left_sum.resize(n);
    right_sum.resize(n);
    dp.resize(n, id_e);
  }

  void make_egde(long long s, long long t, long long w = 1) {
    adj_list[s].push_back({s, t, w, id_e, (long long)adj_list[t].size()});
    adj_list[t].push_back({t, s, w, id_e, (long long)adj_list[s].size() - 1});
  }

  void calculate() {
    dfs1(-1, 0, -1);
    dfs2(-1, 0, -1);
  }

  T f(T t, long long prev, long long now, long long idx) {
    t.first++;
    ll sum = 0;
    for (ll i = 0; i < adj_list[now].size(); i++) {
      if (prev == adj_list[now][i].to)
        continue;
      sum += adj_list[now][i].dp.first;
      t.second *= factorial_inv[adj_list[now][i].dp.first];
    }
    t.second *= factorial[sum];
    return t;
  }

  T merge(T a, T b) { return {a.first + b.first, a.second * b.second}; }

  void make_sum(long long now) {
    long long m = adj_list[now].size();
    left_sum[now].resize(m + 1, id_e);
    right_sum[now].resize(m + 1, id_e);
    for (long long i = 0; i < m; i++) {
      left_sum[now][i + 1] = merge(left_sum[now][i], adj_list[now][i].dp);
    }
    for (long long i = m - 1; i >= 0; i--) {
      right_sum[now][i] = merge(right_sum[now][i + 1], adj_list[now][i].dp);
    }
  }

  void dfs1(long long prev, long long now, long long idx) {
    T ans = id_e;
    for (long long i = 0; i < adj_list[now].size(); i++) {
      if (adj_list[now][i].to == prev)
        continue;
      dfs1(now, adj_list[now][i].to, i);
      ans = merge(ans, adj_list[now][i].dp);
    }
    if (now == 0) {
      make_sum(0);
      dp[0] = f(ans, prev, now, idx);
    } else
      adj_list[prev][idx].dp = f(ans, prev, now, idx);
  }

  void dfs2(long long prev, long long now, long long idx) {
    if (now > 0) {
      adj_list[now][adj_list[prev][idx].reverse_idx].dp =
          f(merge(left_sum[prev][idx], right_sum[prev][idx + 1]), now, prev,
            adj_list[prev][idx].reverse_idx);
      make_sum(now);
      dp[now] = f(left_sum[now].back(), -1, now, -1);
    }
    for (long long i = 0; i < adj_list[now].size(); i++) {
      if (adj_list[now][i].to == prev)
        continue;
      dfs2(now, adj_list[now][i].to, i);
    }
  }
};

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

  ll n;
  cin >> n;
  make_table<MOD>(2e5);
  rerooting<pair<ll, modint<MOD>>> rr(n);
  for (ll i = 0; i < n - 1; i++) {
    ll a, b;
    cin >> a >> b;
    rr.make_egde(a - 1, b - 1);
  }
  rr.calculate();
  for (auto i : rr.dp)
    cout << i.second << '\\n';
}