Problem p02728 (C++) — buggy submission, verdict: Runtime Error

// #include <bits/stdc++.h>
// #define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
// #define int long long
// #define sz(i) (int)(i.size())
// #define F first
// #define S second
// #define L long double
// #define P pair<int, int>
// const int inf = 0x3f3f3f3f3f3f3f3LL;
// const int mod = (int)1e9 + 7;
// using namespace std;
// #if LOCAL
// #include "../../tr.h"
// #else
// #define tr(...)
// #define endl '\\n'
// #endif
// template<class T> void smin(T& a, T val) {if (a > val) a =
// val;}template<class T> void smax(T& a, T val) {if (a < val) a = val;} const
// int N = 55;

// int n;
// vector<int> v[N];

// int lvl[N];
// //if this is graph makes sure to loop for all the unvisited vertices, i.e,
// the graph may be unconnected void dfs(int s, int p, int lvl){
//    ::lvl[lvl]++;
//    for(auto i: v[s]){
//       if(i != p){
//          dfs(i, s, lvl);
//       }
//    }
// }

// int32_t main(){_

//    cin>>n;

//    for (int i = 0; i+1 < n; ++i)
//    {
//       int x, y;
//       cin >> x >> y;
//       v[x].push_back(y);
//       swap(x, y);
//       v[x].push_back(y);
//    }

//    for (int i = 1; i <= n; ++i)
//    {
//       memset(lvl, 0, sizeof lvl);
//       dfs(i, -1, 0);

//       int ans = lvl[0];
//       for (int j = 1; j <= n; ++j)
//       {
//          if(j > 1)
//             lvl[j] += lvl[j-1];
//          tr(i, lvl[j]);
//          if(lvl[j] == 0)
//             continue;
//          ans *= lvl[j];
//       }

//       cout<<ans<<endl;
//    }

//    return 0;
// }
#include <iostream>
#include <vector>
using namespace std;

// #1 Additional explanations regardint the number of topological
// sortings of a tree. The clasic formula using combinations with repetitions
// may be straight forward or more easy to understand, but it may be hard to
// apply it with ease. On the other hand, looking closely at those combinations
// it's easy to see that a lot of the reduce and the final answer looks like
// N! / (subtree_size[1] * subtree_size[2] * .. * subtree_size[n])

typedef long long int64;

const int kMaxN = 2e5 + 10, kMod = 1e9 + 7;

int Pow(int a, int p) {
  int res = 1;
  while (p) {
    if (p & 1) {
      res = (1LL * res * a) % kMod;
    }
    a = (1LL * a * a) % kMod;
    p /= 2;
  }

  return res;
}

int inv_number[kMaxN + 1];
int fact[kMaxN + 1];

// computes X! % kMod and 1 / X % kMod in O(kMaxN)
void Initialise() {
  fact[0] = fact[1] = 1;
  for (int i = 2; i <= kMaxN; i += 1) {
    fact[i] = (1LL * i * fact[i - 1]) % kMod;
  }

  int inv_fact = Pow(fact[kMaxN], kMod - 2);

  for (int i = kMaxN; i; i -= 1) {
    inv_number[i] = 1LL * inv_fact * fact[i - 1] % kMod;
    inv_fact = 1LL * inv_fact * (i) % kMod;
  }

  inv_number[0] = 1;
}

vector<int> neighbour[kMaxN];
bool visited[kMaxN];
int subtree_size[kMaxN];

// roots the tree in node and computes the subtree_size for itself and all it's
// children (unvisited nodes)
void ComputeSubtree(int node) {
  visited[node] = true;
  for (auto itr : neighbour[node]) {
    if (visited[itr]) {
      continue;
    }

    ComputeSubtree(itr);
    subtree_size[node] += subtree_size[itr];
  }

  subtree_size[node] += 1;

  // nice hack. If you only do a DF on a tree you can do this so you don't
  // have to make the visited array equal to false afterwards.
  visited[node] = false;
}

// global answer and n
int64 answer = 0;
int n;

// The answer for node is "sum"
// add it to the global result and change it to match the wanted sum for each
// child and solve for the recursively

vector<int> v;
void Solve(int node, int sum) {
  v[node] = sum;
  visited[node] = true;
  for (auto itr : neighbour[node]) {
    if (visited[itr]) {
      continue;
    }

    // if you have trouble understanding this formula read (#1) on the top of
    // the source. if we move the "root" from node to itr, subtree_size[itr]
    // changes from subtree_size[itr] to n and subtree_size[node] (root) changes
    // from n to .. (n - subtree_size[itr]) we first must get rid of the
    // previous / subtree_size[itr] and just add the new / (n -
    // subtree_size[itr])
    Solve(itr, 1LL * sum * subtree_size[itr] % kMod *
                   inv_number[(n - subtree_size[itr])] % kMod);
  }

  visited[node] = false;
}

int main() {
  Initialise();

  cin >> n;
  v.resize(n);

  for (int i = 1; i < n; i += 1) {
    int a, b;
    cin >> a >> b;
    // I will make the best indexing out there.
    // Like you never saw.
    a -= 1;
    b -= 1;
    neighbour[a].push_back(b);
    neighbour[b].push_back(a);
  }

  const int root = 0;
  ComputeSubtree(root);

  // computing the answer for the root. (node 0, for example, it doesn't matter
  // at all)
  int root_answer = fact[n];
  for (int i = 0; i < n; i += 1) {
    root_answer = 1LL * root_answer * inv_number[subtree_size[i]] % kMod;
  }

  Solve(root, root_answer);

  for (int i = 0; i < n; ++i) {
    cout << v[i] << endl;
  }

  return 0;
}


Error: 0

Fixed submission:

// #include <bits/stdc++.h>
// #define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
// #define int long long
// #define sz(i) (int)(i.size())
// #define F first
// #define S second
// #define L long double
// #define P pair<int, int>
// const int inf = 0x3f3f3f3f3f3f3f3LL;
// const int mod = (int)1e9 + 7;
// using namespace std;
// #if LOCAL
// #include "../../tr.h"
// #else
// #define tr(...)
// #define endl '\\n'
// #endif
// template<class T> void smin(T& a, T val) {if (a > val) a =
// val;}template<class T> void smax(T& a, T val) {if (a < val) a = val;} const
// int N = 55;

// int n;
// vector<int> v[N];

// int lvl[N];
// //if this is graph makes sure to loop for all the unvisited vertices, i.e,
// the graph may be unconnected void dfs(int s, int p, int lvl){
//    ::lvl[lvl]++;
//    for(auto i: v[s]){
//       if(i != p){
//          dfs(i, s, lvl);
//       }
//    }
// }

// int32_t main(){_

//    cin>>n;

//    for (int i = 0; i+1 < n; ++i)
//    {
//       int x, y;
//       cin >> x >> y;
//       v[x].push_back(y);
//       swap(x, y);
//       v[x].push_back(y);
//    }

//    for (int i = 1; i <= n; ++i)
//    {
//       memset(lvl, 0, sizeof lvl);
//       dfs(i, -1, 0);

//       int ans = lvl[0];
//       for (int j = 1; j <= n; ++j)
//       {
//          if(j > 1)
//             lvl[j] += lvl[j-1];
//          tr(i, lvl[j]);
//          if(lvl[j] == 0)
//             continue;
//          ans *= lvl[j];
//       }

//       cout<<ans<<endl;
//    }

//    return 0;
// }
#include <iostream>
#include <vector>
using namespace std;

// #1 Additional explanations regardint the number of topological
// sortings of a tree. The clasic formula using combinations with repetitions
// may be straight forward or more easy to understand, but it may be hard to
// apply it with ease. On the other hand, looking closely at those combinations
// it's easy to see that a lot of the reduce and the final answer looks like
// N! / (subtree_size[1] * subtree_size[2] * .. * subtree_size[n])

typedef long long int64;

const int kMaxN = 1e5, kMod = 1e9 + 7;

int Pow(int a, int p) {
  int res = 1;
  while (p) {
    if (p & 1) {
      res = (1LL * res * a) % kMod;
    }
    a = (1LL * a * a) % kMod;
    p /= 2;
  }

  return res;
}

int inv_number[kMaxN + 1];
int fact[kMaxN + 1];

// computes X! % kMod and 1 / X % kMod in O(kMaxN)
void Initialise() {
  fact[0] = fact[1] = 1;
  for (int i = 2; i <= kMaxN; i += 1) {
    fact[i] = (1LL * i * fact[i - 1]) % kMod;
  }

  int inv_fact = Pow(fact[kMaxN], kMod - 2);

  for (int i = kMaxN; i; i -= 1) {
    inv_number[i] = 1LL * inv_fact * fact[i - 1] % kMod;
    inv_fact = 1LL * inv_fact * (i) % kMod;
  }

  inv_number[0] = 1;
}

vector<int> neighbour[kMaxN];
bool visited[kMaxN];
int subtree_size[kMaxN];

// roots the tree in node and computes the subtree_size for itself and all it's
// children (unvisited nodes)
void ComputeSubtree(int node) {
  visited[node] = true;
  for (auto itr : neighbour[node]) {
    if (visited[itr]) {
      continue;
    }

    ComputeSubtree(itr);
    subtree_size[node] += subtree_size[itr];
  }

  subtree_size[node] += 1;

  // nice hack. If you only do a DF on a tree you can do this so you don't
  // have to make the visited array equal to false afterwards.
  visited[node] = false;
}

// global answer and n
int64 answer = 0;
int n;

// The answer for node is "sum"
// add it to the global result and change it to match the wanted sum for each
// child and solve for the recursively

vector<int> v;
void Solve(int node, int sum) {
  v[node] = sum;
  visited[node] = true;
  for (auto itr : neighbour[node]) {
    if (visited[itr]) {
      continue;
    }

    // if you have trouble understanding this formula read (#1) on the top of
    // the source. if we move the "root" from node to itr, subtree_size[itr]
    // changes from subtree_size[itr] to n and subtree_size[node] (root) changes
    // from n to .. (n - subtree_size[itr]) we first must get rid of the
    // previous / subtree_size[itr] and just add the new / (n -
    // subtree_size[itr])
    Solve(itr, 1LL * sum * subtree_size[itr] % kMod *
                   inv_number[(n - subtree_size[itr])] % kMod);
  }

  visited[node] = false;
}

int main() {
  Initialise();

  cin >> n;
  v.resize(n);

  for (int i = 1; i < n; i += 1) {
    int a, b;
    cin >> a >> b;
    // I will make the best indexing out there.
    // Like you never saw.
    a -= 1;
    b -= 1;
    neighbour[a].push_back(b);
    neighbour[b].push_back(a);
  }

  const int root = 0;
  ComputeSubtree(root);

  // computing the answer for the root. (node 0, for example, it doesn't matter
  // at all)
  int root_answer = fact[n];
  for (int i = 0; i < n; i += 1) {
    root_answer = 1LL * root_answer * inv_number[subtree_size[i]] % kMod;
  }

  Solve(root, root_answer);

  for (int i = 0; i < n; ++i) {
    cout << v[i] << endl;
  }

  return 0;
}