#include <iostream>
#include <iomanip>
#include <string>
#include <stack>
#include <vector>
#include <complex>
#include <math.h>
#include <stdio.h>
#include <algorithm>
#include <utility>
#include <functional>
#include <iterator>
#include <map>
#include <set>
#include <queue>
#include <list>
#include <regex>
#include <limits>
#include <time.h>
#include <cstdint>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <limits.h>
using namespace std;
using pii  = pair<int,int>;
using ll=long long;
using ld=long double;
#define pb push_back
#define mp make_pair
#define sc second
#define fr first
#define stpr setprecision
#define cYES cout<<"YES"<<endl
#define cNO cout<<"NO"<<endl
#define cYes cout<<"Yes"<<endl
#define cNo cout<<"No"<<endl
#define rep(i,n) for(ll i=0;i<(n);++i)
#define Rep(i,a,b) for(ll i=(a);i<(b);++i)
#define rrep(i,n) for(ll i=n-1;i>=0;i--)
#define rRep(i,a,b) for(ll i=a;i>=b;i--)
#define crep(i) for(char i='a';i<='z';++i)
#define psortsecond(A,N) sort(A,A+N,[](const pii &a, const pii &b){return a.second<b.second;});
#define ALL(x) (x).begin(),(x).end()
#define debug(v) cout<<#v<<":";for(auto x:v){cout<<x<<' ';}cout<<endl;
#define endl '\n'
int ctoi(const char c){
  if('0' <= c && c <= '9') return (c-'0');
  return -1;
}
ll gcd(ll a,ll b){return (b == 0 ? a : gcd(b, a%b));}
ll lcm(ll a,ll b){return a*b/gcd(a,b);}
constexpr ll MOD=1000000007;
constexpr ll INF=1000000011;
constexpr ll MOD2=998244353;
constexpr ll LINF = 1001002003004005006ll;
constexpr ld EPS=10e-8;
template <class T, class U> inline bool chmax(T& lhs, const U& rhs) { if (lhs < rhs) { lhs = rhs; return 1; } return 0; }
template <class T, class U> inline bool chmin(T& lhs, const U& rhs) { if (lhs > rhs) { lhs = rhs; return 1; } return 0; }
template<typename T> istream& operator>>(istream& is,vector<T>& v){for(auto&& x:v)is >> x;return is;}
template<typename T,typename U> istream& operator>>(istream& is, pair<T,U>& p){ is >> p.first; is >> p.second; return is;}
template<typename T,typename U> ostream& operator>>(ostream& os, const pair<T,U>& p){ os << p.first << ' ' << p.second; return os;}
template<class T> ostream& operator<<(ostream& os, vector<T>& v){
  for(auto i=begin(v); i != end(v); ++i){
    if(i !=begin(v)) os << ' ';
    os << *i;
  }
  return os;
}

template <std::uint_fast64_t Modulus> class modint {
  using u64 = std::uint_fast64_t;

public:
  u64 a;

  constexpr modint(const u64 x = 0) noexcept : a(x % Modulus) {}
  constexpr u64 &value() noexcept { return a; }
  constexpr const u64 &value() const noexcept { return a; }
  constexpr modint operator+(const modint rhs) const noexcept {
    return modint(*this) += rhs;
  }
  constexpr modint operator-(const modint rhs) const noexcept {
    return modint(*this) -= rhs;
  }
  constexpr modint operator*(const modint rhs) const noexcept {
    return modint(*this) *= rhs;
  }
  constexpr modint operator/(const modint rhs) const noexcept {
    return modint(*this) /= rhs;
  }
  constexpr modint &operator+=(const modint rhs) noexcept {
    a += rhs.a;
    if (a >= Modulus) {
      a -= Modulus;
    }
    return *this;
  }
  constexpr modint &operator-=(const modint rhs) noexcept {
    if (a < rhs.a) {
      a += Modulus;
    }
    a -= rhs.a;
    return *this;
  }
  constexpr modint &operator*=(const modint rhs) noexcept {
    a = a * rhs.a % Modulus;
    return *this;
  }
  constexpr modint &operator/=(modint rhs) noexcept {
    u64 exp = Modulus - 2;
    while (exp) {
      if (exp % 2) {
        *this *= rhs;
      }
      rhs *= rhs;
      exp /= 2;
    }
    return *this;
  }
};

ll MODX;

//  いじくる部分ここから
using T = ll;
T identity=1;    // 単位元
bool Commutative_group=0;  //可換群か否か
T Inverce;  //逆元

T merge(T left,T right){
  return (left*right)%MODX;
}

T addNode(T value,ll nodeID){
  return (value+1)%MODX;
}
//  いじくる部分ここまで


ll nodeCount;    // 辺の配列
vector<vector<ll>> E;  // 普通の隣接している点の配列
vector<vector<ll>> indexE;  // adjacents[i][j](iのj番目の隣接頂点)にとって、iが何番目の隣接頂点か
vector<vector<T>> childSubtreeRes;  // iを親とし、adjacents[i][j]を根とした部分木の値 
vector<T> nodeRes;  // iを根としたときの結果結果
vector<ll> parents;  // 親
vector<ll> order; // 行きがけ順
stack<ll> Stk;  // dfs用のstack


int main(){
  ll N;
  // 初期化と入力と前処理
  cin >> N >> MODX;
  if(N==1){   // ここに気をつける
    cout << 1 << endl;
    return 0;
  }
  nodeCount=N;
  parents = vector<ll> (N);
  E = vector<vector<ll>> (nodeCount,vector<ll> (0));
  indexE = vector<vector<ll>> (nodeCount,vector<ll> (0));
  childSubtreeRes = vector<vector<T>> (nodeCount,vector<T> (0));
  nodeRes = vector<T> (nodeCount);
  rep(i,N-1){
    ll A,B;
    cin >> A >> B;
    A--;B--;
    indexE[A].pb(E[B].size());
    indexE[B].pb(E[A].size());
    E[A].pb(B);
    E[B].pb(A);
  }
  rep(i,N){
    childSubtreeRes[i]=vector<T> (E[i].size());
  }

  //0を根としたdfs　行きがけ順を保存する
  Stk.push(0);
  parents[0] = -1;
  while(Stk.size()){
    ll node = Stk.top();
    Stk.pop();
    order.pb(node);
    for(ll i=0;i<E[node].size();i++){
      ll to = E[node][i];
      if( to == parents[node] ) continue;
      Stk.push(to);
      parents[to]=node;
    }
  }

  //帰りがけ順で部分木の値を求めていく
  for(int i=order.size()-1;i>=1;i--){
    ll node = order[i];
    ll parent = parents[node];
    T result = identity;
    ll parentIndex = -1;
    for (int j=0;j<E[node].size();j++){       //隣接する点を調べる
      //もし隣接する点が親だったら、親のindexの記録だけする
      if(E[node][j] == parent) {parentIndex = j; continue;}
      result = merge(result,childSubtreeRes[node][j]);
    }
    childSubtreeRes[parent][indexE[node][parentIndex]]=addNode(result,node);
  }

  //行きがけ順で頂点の値を確定させていく
  for(int i=0;i<order.size();i++){
    ll node = order[i];
    // 可換群ならさらに早くできる
    if (Commutative_group){}
    else {
      ll node = order[i];
      //後ろからの累積和を格納する配列
      vector<T> accumsFromTail(E[node].size());
      accumsFromTail[accumsFromTail.size() - 1] = identity;
      for(int j=accumsFromTail.size()-1;j>=1;j--) accumsFromTail[j-1] =merge(childSubtreeRes[node][j],accumsFromTail[j]);
      //前からの累積和を持つ変数
      T accum = identity;
      for(int j=0;j<accumsFromTail.size();j++){
        //adjacents[node][j]が親、nodeが子の部分木について計算する
        //累積をマージして子部分木の値をマージし終えた後、頂点を追加する
        T result = addNode(merge(accum,accumsFromTail[j]),node);
        //その値を、親が持っている配列に結果を格納する(親にとって自分が何番目の隣接頂点なのかを調べて格納)
        childSubtreeRes[E[node][j]][indexE[node][j]] = result;
        //累積を更新
        accum = merge(accum, childSubtreeRes[node][j]);
      }
      //最後まで累積しきったものはnodeの子部分木を全てマージしたものになっているので、それに頂点を追加するとnodeの値となる
      nodeRes[node] = addNode(accum, node);
    }
  }

  // 出力
  rep(i,N){
    cout << (nodeRes[i]-1+MODX)%MODX << endl;
  }

  return 0;
}

Measured memory_bytes: 25996