library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub matumoto1234/library

:heavy_check_mark: test/atcoder/other/edpc/V.test.cpp

Depends on

Code

#define PROBLEM "https://atcoder.jp/contests/dp/tasks/dp_v"
#include <bits/stdc++.h>
using namespace std;

#include "dp/re-rooting-dp.hpp"
using namespace matumoto;

using ll = long long;
ll m;

ll op(ll a, ll b) {
  return (a * b) % m;
}

ll e() {
  return 1;
}

ll add_node(ll result, int node) {
  return result + 1;
}

int main() {
  ll n;
  cin >> n >> m;

  if (n == 1) {
    cout << 1 << endl;
    return 0;
  }

  ReRootingDP<ll, add_node, op, e> dp(n);

  for (int i = 0; i < n - 1; i++) {
    int x, y;
    cin >> x >> y;

    x--, y--;

    dp.add_edge(x, y, 1);
    dp.add_edge(y, x, 1);
  }

  dp.build();

  for (int i = 0; i < n; i++) {
    // 余分に add_node した(存在しない親に対して自分を含めた結果を返している)のがあるので、その分を -1
    ll ans = dp[i] - 1;
    ans %= m;
    cout << ans << endl;
  }
}
#line 1 "test/atcoder/other/edpc/V.test.cpp"
#define PROBLEM "https://atcoder.jp/contests/dp/tasks/dp_v"
#include <bits/stdc++.h>
using namespace std;

#line 2 "dp/re-rooting-dp.hpp"

#line 2 "dp/base.hpp"

namespace matumoto {
  using namespace std;
}
#line 4 "dp/re-rooting-dp.hpp"

#line 9 "dp/re-rooting-dp.hpp"

namespace matumoto {
  // TODO verify:EDPC-V, ABC220-F, ABC160-F
  // add_node: 自身の値を追加して親方向へ渡す関数 (T result, int index) |-> T
  // op: 二項演算 (monoid)
  // e: opに関する単位元
  template <typename T, T (*add_node)(T, int), T (*op)(T, T), T (*e)()>
  class ReRootingDP {
    // order と parents の前計算
    void dfs(int root) {
      int index = 0;
      stack<int> s;
      s.push(root);
      m_parents[root] = -1;

      while (not s.empty()) {
        int node = s.top();
        s.pop();

        m_order[index++] = node;
        for (auto [adjacent, ignore]: m_tree[node]) {
          if (adjacent == m_parents[node])
            continue;
          s.push(adjacent);
          m_parents[adjacent] = node;
        }
      }
    }

    // 根の値を求めるために全頂点の子方向の値を帰りがけ順で求める
    // child_subtree_results[node][i] (頂点nodeのi番目の子部分木の値) が求まる
    // ただし、子方向を親としたときの child_subtree_results[node][i] は求まらない
    void post_order(int root) {
      vector<int> reversed_order = m_order;
      reverse(reversed_order.begin(), reversed_order.end());

      for (int node: reversed_order) {
        if (node == root)
          continue;

        int parent = m_parents[node];
        int parent_index = -1;
        T result = e();

        for (int i = 0; i < (int)m_tree[node].size(); i++) {
          int to = m_tree[node][i].first;
          if (to == parent) {
            parent_index = i;
            continue;
          }

          result = op(result, m_child_subtree_results[node][i]);
        }

        assert(parent_index != -1);
        m_child_subtree_results[parent][m_index_for_adjacents[node][parent_index]] = add_node(result, node);
      }
    }

    // 全頂点の親方向の値を両側累積を使って求める(行きがけ順)
    // node_results[node] が求まる
    void pre_order() {
      for (int node: m_order) {
        int size = m_tree[node].size();

        if (size == 0)
          continue;

        vector<T> accums_front(size + 1, e()), accums_back(size, e());

        for (int i = 0; i < size; i++) {
          T child_subtree_result = m_child_subtree_results[node][i];
          accums_front[i + 1] = op(accums_front[i], child_subtree_result);
        }
        for (int i = size - 1; i >= 1; i--) {
          T child_subtree_result = m_child_subtree_results[node][i];
          accums_back[i - 1] = op(accums_back[i], child_subtree_result);
        }

        for (int i = 0; i < size; i++) {
          T result = add_node(op(accums_front[i], accums_back[i]), node);

          int parent = m_tree[node][i].first;
          int index_from_parent = m_index_for_adjacents[node][i];

          m_child_subtree_results[parent][index_from_parent] = result;
        }
        T accum_child_subtree_result = accums_front.back();
        m_node_results[node] = add_node(accum_child_subtree_result, node);
      }
    }

  public:
    using Edge = pair<int, T>;
    vector<vector<Edge>> m_tree;
    vector<vector<int>> m_index_for_adjacents;
    vector<vector<T>> m_child_subtree_results;
    vector<int> m_parents, m_order;
    vector<T> m_node_results;

    ReRootingDP(int n): m_tree(n), m_index_for_adjacents(n), m_parents(n), m_order(n), m_node_results(n, e()) {}

    // Directed edge
    void add_edge(int from, int to, T cost) {
      m_tree[from].emplace_back(to, cost);
      m_index_for_adjacents[to].emplace_back(m_tree[from].size() - 1);
    }

    void build() {
      int size = m_tree.size();
      assert(size != 0);
      m_child_subtree_results.resize(size);
      for (int i = 0; i < size; i++) {
        m_child_subtree_results[i].assign(m_tree[i].size(), e());
      }

      dfs(/* root = */ 0);
      post_order(/* root = */ 0);
      pre_order();
    }

    T operator[](int node) {
      return m_node_results[node];
    }
  };
} // namespace matumoto
#line 6 "test/atcoder/other/edpc/V.test.cpp"
using namespace matumoto;

using ll = long long;
ll m;

ll op(ll a, ll b) {
  return (a * b) % m;
}

ll e() {
  return 1;
}

ll add_node(ll result, int node) {
  return result + 1;
}

int main() {
  ll n;
  cin >> n >> m;

  if (n == 1) {
    cout << 1 << endl;
    return 0;
  }

  ReRootingDP<ll, add_node, op, e> dp(n);

  for (int i = 0; i < n - 1; i++) {
    int x, y;
    cin >> x >> y;

    x--, y--;

    dp.add_edge(x, y, 1);
    dp.add_edge(y, x, 1);
  }

  dp.build();

  for (int i = 0; i < n; i++) {
    // 余分に add_node した(存在しない親に対して自分を含めた結果を返している)のがあるので、その分を -1
    ll ans = dp[i] - 1;
    ans %= m;
    cout << ans << endl;
  }
}
Back to top page