Problem:
Stamp Rally
You are in charge of $N$ lodges and the road that connects each lodge. Each lodge has a number from 1 to $N$. There are $N-1$ paths in total. All paths can be traveled in both directions. Also, from any lodge, you can reach other lodges by taking some of the paths.
You decide to start a stamp rally by placing stamps at all the lodges so that the lodge visitors can enjoy themselves. The rules of this stamp rally are as follows.
Visitors choose a number of mountain lodges. At this time, the number of lodges that can be chosen is from 2 to $N$. After that, they move to one of the lodges they have chosen and start the stamp rally from there.
During the stamp rally, visitors move between the lodges along a path. They will visit all the lodges that they pass during their journey and stamp them there.
If the user visits a lodge that has already been stamped, the stamp rally fails and ends at that point.
When you have visited all the lodges you have chosen, the stamp rally will be successful and you will receive a prize.
In order to make the stamp rally successful, users need to choose the correct route to visit the mountain lodges. However, depending on how the mountain lodges are chosen, it will not be possible to succeed no matter how the route is chosen. Therefore, we decided to only allow people to choose mountain lodges that would allow them to successfully complete the stamp rally. How many such combination of mountain lodges are there?
You are given the information on the number of lodges and the paths that connect the lodges directly to each other will be given. When choosing from 2 to $N$ mountain lodges each, find the number of ways to choose mountain lodges that would allow the stamp rally to be successful for each number of lodges chosen.
Input
The input is given in the following form.
$N$
$s_1$ $t_1$
$s_2$ $t_2$
:
$s_{N-1}$ $t_{N-1}$
In the first line, the number of lodges $N$ ($2 \leq N \leq 200,000$) is given. In the following $N-1$ lines, the information of the path directly connecting the two lodges is given. $s_i$ and $t_i$ ($1 \leq s_i < t_i \leq N$) are the numbers of the two lodges connected by the $i$-th path. For any two lodges, there should be no more than one path that directly connects them.
Output
The output consists of $N-1$ lines, where the $i$-th line is the number of ways to choose lodge that would make the stamp rally successful if $i+1$ lodges were chosen. 
 Divide the answer by 998,244,353 and output the remainder.
Sample Input and Output
Sample Input
5
1 2
2 3
3 4
3 5
Sample Output
10
8
2
0

Submitted solutions:

code_snippet: // AOJ #0452 Stamp Rally
// 2025.4.19

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 998244353, G = 3;
const ll MERGE_THRESHOLD = 1000000LL;

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {
	int n = 0; int c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(int n) {
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

ll modpow(ll a, ll e = MOD - 2) {
    ll r = 1;
    while (e) {
        if (e & 1) r = r * a % MOD;
        a = a * a % MOD;
        e >>= 1;
    }
    return r;
}

void ntt(vector<ll> &a, bool inv) {
    int n = a.size(), j = 0;
    for (int i = 1; i < n; i++) {
        int bit = n >> 1;
        for (; j & bit; bit >>= 1) j ^= bit;
        j |= bit;
        if (i < j) swap(a[i], a[j]);
    }
    for (int len = 1; len < n; len <<= 1) {
        ll w0 = modpow(G, (MOD - 1) / (len << 1));
        if (inv) w0 = modpow(w0);
        vector<ll> w(len);
        w[0] = 1;
        for (int i = 1; i < len; i++) w[i] = w[i - 1] * w0 % MOD;
        for (int i = 0; i < n; i += len << 1) {
            for (int k = 0; k < len; k++) {
                ll u = a[i + k];
                ll v = a[i + k + len] * w[k] % MOD;
                a[i + k] = (u + v < MOD ? u + v : u + v - MOD);
                a[i + k + len] = (u - v >= 0 ? u - v : u - v + MOD);
            }
        }
    }
    if (inv) {
        ll invn = modpow(n);
        for (ll &x : a) x = x * invn % MOD;
    }
}

vector<ll> conv(const vector<ll> &A, const vector<ll> &B) {
    int na = A.size(), nb = B.size(), n = 1;
    while (n < na + nb - 1) n <<= 1;
    vector<ll> a(A.begin(), A.end()), b(B.begin(), B.end());
    a.resize(n); b.resize(n);
    ntt(a, false);
    ntt(b, false);
    for (int i = 0; i < n; i++) a[i] = a[i] * b[i] % MOD;
    ntt(a, true);
    a.resize(na + nb - 1);
    return a;
}

int n;
vector<vector<int>> g;
vector<bool> used;
vector<int> sz;
vector<ll> freq;
const ll INV2 = (MOD + 1) / 2;

void dfs_sz(int u, int p) {
    sz[u] = 1;
    for (int v : g[u]) if (v != p && !used[v]) {
        dfs_sz(v, u);
        sz[u] += sz[v];
    }
}

int find_centroid(int u, int p, int tot) {
    for (int v : g[u]) if (v != p && !used[v] && sz[v] > tot / 2) return find_centroid(v, u, tot);
    return u;
}

void dfs_dist(int u, int p, int d, vector<ll> &ds) {
    if ((int)ds.size() <= d) ds.resize(d + 1);
    ds[d]++;
    for (int v : g[u]) if (v != p && !used[v]) dfs_dist(v, u, d + 1, ds);
}

void decomp(int root) {
    dfs_sz(root, -1);
    int c = find_centroid(root, -1, sz[root]);
    used[c] = true;

    vector<ll> cnt(1, 1);
    for (int v : g[c]) if (!used[v]) {
        vector<ll> ds;
        dfs_dist(v, c, 1, ds);
        int s = ds.size();
        int t = cnt.size();

        if (1LL * s * t <= MERGE_THRESHOLD) {
            for (int i = 1; i < s; i++) {
                if (!ds[i]) continue;
                for (int j = 0; j < t; j++) freq[i + j] = (freq[i + j] + ds[i] * cnt[j]) % MOD;
            }
        } else {
            auto C = conv(ds, cnt);
            for (int k = 0, L = C.size(); k < L; k++) freq[k] = (freq[k] + C[k]) % MOD;
        }
        if (s > t) cnt.resize(s);
        for (int i = 1; i < s; i++) {
            cnt[i] += ds[i];
            if (cnt[i] >= MOD) cnt[i] -= MOD;
        }
    }
    for (int v : g[c]) if (!used[v]) decomp(v);
}

int main() {
    n = Cin();
    g.assign(n, {});
    for (int i = 0; i < n - 1; i++) {
        int u = Cin()-1, v = Cin()-1;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    used.assign(n, false);
    sz.assign(n, 0);
    freq.assign(n, 0);

    decomp(0);

    vector<ll> fact(n+1,1), ifact(n+1,1);
    for (int i = 1; i <= n; i++) fact[i] = fact[i-1] * i % MOD;
    ifact[n] = modpow(fact[n]);
    for (int i = n; i > 0; i--) ifact[i-1] = ifact[i] * i % MOD;

    int D = n - 1;
    vector<ll> Gv(D);
    for (int i = 0; i < D; i++) Gv[i] = freq[i+1];

    vector<ll> F(D);
    for (int i = 0; i < D; i++) F[i] = Gv[i] * fact[i] % MOD;

    vector<ll> Rv = F;
    reverse(Rv.begin(), Rv.end());
    vector<ll> Iv(D);
    for (int j = 0; j < D; j++) Iv[j] = ifact[j];

    auto W = conv(Rv, Iv);

    vector<ll> H(D);
    for (int j = 0; j < D; j++) {
        ll v = W[D-1-j] % MOD;
        H[j] = v * ifact[j] % MOD;
    }

    for (int k = 2; k <= n; k++) Cout(H[k-2]);
    return 0;
}
accuracy: 1
time_ms: 380
memory_kb: 53492
final_rank: 3

code_snippet: #include "bits/stdc++.h"
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
#define rep(i, m, n) for (ll i = (ll)m; i < (ll)n; i++)
#define drep(i, m, n) for (ll i = m - 1; i >= n; i--)
#define Endl endl
#define all(a) a.begin(), a.end()
#define pr(i, j) make_pair(i, j)
#define isin(x, l, r) (l <= x && x < r)
#define chmin(a, b) a = min(a, b)
#define chmax(a, b) a = max(a, b)
#define srt(ar) sort(ar.begin(), ar.end())
#define rev(ar) reverse(ar.begin(), ar.end())
#define jge(f, s, t) cout << (f ? s : t) << endl
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#define printar(ar)             \
    do                          \
    {                           \
        for (auto dbg : ar)     \
        {                       \
            cout << dbg << " "; \
        }                       \
        cout << endl;           \
    } while (0)
const ll inf = 1e18;
const ld pi = 3.14159265358979;
const ld eps = 1e-9;
template <class T, ll n, ll idx = 0>
auto make_vec(const ll (&d)[n], const T &init) noexcept
{
    if constexpr (idx < n)
        return std::vector(d[idx], make_vec<T, n, idx + 1>(d, init));
    else
        return init;
}

template <class T, ll n>
auto make_vec(const ll (&d)[n]) noexcept
{
    return make_vec(d, T{});
}
//////////////// 以下を貼る ////////////////
template <class T>
size_t HashCombine(const size_t seed, const T &v)
{
    return seed ^ (std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
/* pair用 */
template <class T, class S>
struct std::hash<std::pair<T, S>>
{
    size_t operator()(const std::pair<T, S> &keyval) const noexcept
    {
        return HashCombine(std::hash<T>()(keyval.first), keyval.second);
    }
};

class CentroidDecomposition
{
private:
    void build_inside(vector<int> &lavels, vector<vector<int>> &g, int from)
    {
        int x = centroid(g);
        int r = lavels[x];
        /*
        lavels_each[r] = lavels;
        graph_each[r] = g;
        重いので使用不可！
        */
        if (from != -1)
        {
            centroid_graph[r].push_back(from);
            centroid_graph[from].push_back(r);
            centroid_graph_belong[r] = from;
        }
        else
        {
            G = r;
        }
        vector<int> visit_t(lavels.size(), -1);
        rep(i, 0, g[x].size())
        {
            int next = g[x][i];
            vector<int> lavels_new;
            vector<int> v_g;
            queue<pair<int, int>> bfs;
            bfs.push(pr(next, x));
            int t = 0;
            while (!bfs.empty())
            {
                int now = bfs.front().first;
                int prev = bfs.front().second;
                bfs.pop();
                lavels_new.push_back(lavels[now]);
                v_g.push_back(now);
                visit_t[now] = t;
                t++;
                for (auto v : g[now])
                {
                    if (v != prev)
                    {
                        bfs.push(pr(v, now));
                    }
                }
            }
            vector<vector<int>> g_new(lavels_new.size());
            bfs.push(pr(next, x));
            while (!bfs.empty())
            {
                int now = bfs.front().first;
                int prev = bfs.front().second;
                int nx = visit_t[now];
                bfs.pop();
                for (auto v : g[now])
                {
                    if (v != prev)
                    {
                        g_new[nx].push_back(visit_t[v]);
                        g_new[visit_t[v]].push_back(nx);
                        bfs.push(pr(v, now));
                    }
                }
            }
            build_inside(lavels_new, g_new, r);
        }
    }
    int centroid(vector<vector<int>> &g)
    {
        int N = g.size();
        vector<int> sz(N);
        vector<int> centroid;
        function<void(int, int)> dfs = [&](int u, int prev)
        {
            sz[u] = 1;
            bool is_centroid = true;
            for (auto v : g[u])
            {
                if (v != prev)
                {
                    dfs(v, u);
                    sz[u] += sz[v];
                    if (sz[v] > N / 2)
                    {
                        is_centroid = false;
                    }
                }
            }
            if (N - sz[u] > N / 2)
            {
                is_centroid = false;
            }
            if (is_centroid)
            {
                centroid.push_back(u);
            }
        };
        dfs(0, -1);
        return centroid[0];
    }

public:
    /*
        vector<vector<int>> lavels_each;        // graph_eachのラベル
        vector<vector<vector<int>>> graph_each; // 頂点iが重心(かつ根)となっているような木を返す
        重いので使用不可！
    */
    vector<vector<int>> centroid_graph; // 重心同士を結んだ木
    vector<int> centroid_graph_belong;  // 重心同士を結んだ木の、頂点iの親
    int G;                              // 元のグラフの重心
    void build(vector<vector<int>> &g)
    {
        int N = g.size();
        /*
        lavels_each.resize(N);
        graph_each.resize(N);
        */
        centroid_graph.resize(N);
        centroid_graph_belong.resize(N, -1);
        vector<int> lavels(N);
        rep(i, 0, N)
        {
            lavels[i] = i;
        }
        build_inside(lavels, g, -1);
    }
    void debug()
    {
        rep(i, 0, centroid_graph.size())
        {
            printar(centroid_graph[i]);
        }
    }
    CentroidDecomposition(vector<vector<int>> &g)
    {
        build(g);
    }
};

class Num
{
private:
    vector<ll> fac_mod_ar = {};
    vector<ll> mobius_ar = {};
    vector<bool> isprime_ar = {};
    vector<ll> base_2_ar = {};

public:
    // gcd(a,b)を返す
    ll gcd(ll a, ll b)
    {
        if (a == 0 || b == 0)
            return 0;
        if (b > a)
            swap(a, b);
        if (a % b == 0)
            return b;
        else
        {
            return gcd(b, a % b);
        }
    }
    // lcm(a,b)を返す
    ll lcm(ll a, ll b)
    {
        return b / gcd(a, b) * a;
    }
    // a^b (modp)を返す
    ll exp(ll a, ll b, ll p)
    {
        if (b == 0)
            return 1;
        ll l = log2((b));
        ll num = l + 1;
        // cout << num << endl;
        base_2_ar.resize(num);
        base_2_ar[0] = a;
        rep(i, 1, num)
        {
            base_2_ar[i] = base_2_ar[i - 1] * base_2_ar[i - 1];
            base_2_ar[i] %= p;
            // cout << base_2[i] << endl;
        }
        ll ret = 1;
        rep(i, 0, num)
        {
            // cout << (b >> i) % 2;
            if ((b >> i) % 2 == 1)
                ret *= base_2_ar[i];
            ret %= p;
        }
        return ret;
    }
    // ax+by=gcd(a,b)を満たすx,yを求める
    ll ax_by(ll a, ll b, ll &x, ll &y)
    {
        if (b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        ll d = ax_by(b, a % b, y, x);
        y -= a / b * x;
        return d;
    }
    // a(mod m1),b(modm2)なるxを求める 中国剰余定理
    ll CRT(ll a, ll m1, ll b, ll m2)
    {
        ll x, y;
        ax_by(m1, m2, x, y);
        y *= (a - b);
        x %= m2;
        x *= (b - a);
        x %= m2;
        ll k = (m1 * x + a);
        k %= m1 * m2;
        k += m1 * m2;
        k %= m1 * m2;
        return k;
    }
    // mod pにおけるaの逆元を求める
    ll inv(ll a, ll p)
    {
        ll ret, b;
        ax_by(a, p, ret, b);
        ret %= p;
        ret += p;
        ret %= p;
        return ret;
    }

    // φ(n)を求める
    ll phi(ll n)
    {
        ll ret = n;
        for (ll i = 2; i * i <= n; i++)
        {
            if (n % i == 0)
            {
                while (n % i == 0)
                    n /= i;
                ret *= (i - 1);
                ret /= i;
            }
        }
        if (n != 1)
        {
            ret *= (n - 1);
            ret /= n;
        }
        return ret;
    }
    // 素数判定のための前計算 O(nloglogn)
    void isprime_init(ll n)
    {
        if (isprime_ar.size() >= n + 1)
            return;
        isprime_ar.resize(n + 1, true);
        isprime_ar[0] = false;
        isprime_ar[1] = false;
        for (ll i = 2; i <= n; i++)
        {
            if (isprime_ar[i])
            {
                for (ll j = 2 * i; j <= n; j += i)
                {
                    isprime_ar[j] = false;
                }
            }
        }
    }
    // nCrmodのための前計算 O(n)
    void nCrmod_init(ll n, ll p)
    {
        if (fac_mod_ar.size() >= n + 1)
            return;
        fac_mod_ar.resize(0);
        fac_mod_ar.resize(n + 1);
        fac_mod_ar[0] = 1;
        rep(i, 1, n + 1)
        {
            fac_mod_ar[i] = fac_mod_ar[i - 1] * i;
            fac_mod_ar[i] %= p;
        }
    }
    // メビウス関数のための前計算 O(nloglogn)
    void mobius_init(ll n)
    {
        if (mobius_ar.size() >= n + 1)
            return;
        mobius_ar.resize(n + 1, 1);
        isprime_init(n);
        mobius_ar[1] = 1;
        for (ll i = 2; i <= n; i++)
        {
            if (!isprime(i))
                continue;
            mobius_ar[i] = -1;
            for (ll j = 2 * i; j <= n; j += i)
            {
                if (j % (i * i) == 0)
                    mobius_ar[j] = 0;
                else
                    mobius_ar[j] *= -1;
            }
        }
    }
    // nの素数判定 前計算が必要
    bool isprime(ll n)
    {
        isprime_init(n);
        return isprime_ar[n];
    }
    // n! mod pを求める 前計算が必要
    ll fac(ll n, ll p)
    {
        nCrmod_init(n, p);
        return fac_mod_ar[n];
    }
    // nCr(mod p)を求める 前計算が必要
    ll nCrmod(ll n, ll r, ll p)
    {
        nCrmod_init(n, p);
        ll ret = 1;
        ret *= fac_mod_ar[n];
        ret %= p;
        ret *= inv(fac_mod_ar[r], p);
        ret %= p;
        ret *= inv(fac_mod_ar[n - r], p);
        ret %= p;
        return ret;
    }
    // μ(n)を求める　前計算が必要
    ll mobius(ll n)
    {
        mobius_init(n);
        return mobius_ar[n];
    }
};
////////////////////////////////////////////////

class FastFourierTransform
{
private:
    ll P = 998244353;
    ll R = 1107296257;
    vector<ll> r_p;
    vector<ll> r_r;
    vector<ll> r_p_inv;
    vector<ll> r_r_inv;
    bool f_p = false;
    bool f_r = false;
    ll mod_inv(ll n, ll p)
    {
        ll b = p, u = 1, v = 0;
        while (b)
        {
            ll t = n / b;
            n -= t * b;
            swap(n, b);
            u -= t * v;
            swap(u, v);
        }
        u %= p;
        if (u < 0)
            u += p;
        return u;
    }
    void dft(vector<complex<ld>> &func, bool isinv)
    {
        ll n = func.size();
        if (n == 1)
        {
            return;
        }
        else
        {
            vector<complex<ld>> a, b;
            rep(i, 0, n)
            {
                if (i % 2 == 0)
                {
                    a.push_back(func[i]);
                }
                else
                {
                    b.push_back(func[i]);
                }
            }
            dft(a, isinv);
            dft(b, isinv);
            complex<ld> now = 1;
            ld theta = (2.0 * acos(-1)) / n;
            if (isinv)
            {
                theta *= -1.0;
            }
            complex<ld> z = polar((ld)1.0, theta);
            rep(i, 0, n)
            {
                func[i] = a[i % (n / 2)] + now * b[i % (n / 2)];
                now *= z;
            }
            return;
        }
    }
    void nft_int(vector<ll> &func, bool isinv, ll p)
    {
        ll n = func.size();
        if (n == 1)
        {
            return;
        }
        else
        {
            ll x = log2(n);
            rep(i, 0, n)
            {
                ll j = 0;
                rep(k, 0, x)
                {
                    j |= ((i >> k) & 1LL) << (x - 1 - k);
                }
                if (i < j)
                {
                    swap(func[i], func[j]);
                }
            }
            rep(i, 0, x)
            {
                ll b = (1LL << i);
                ll now = 1;
                ll z = -1;
                if (p == P)
                {
                    z = r_p[i + 1];
                    if (isinv)
                    {
                        z = r_p_inv[i + 1];
                    }
                }
                else
                {
                    z = r_r[i + 1];
                    if (isinv)
                    {
                        z = r_r_inv[i + 1];
                    }
                }
                rep(j, 0, b)
                {
                    for (int k = 0; k < n; k += b * 2)
                    {
                        ll s = func[j + k];
                        ll t = func[j + k + b] * now;
                        t %= p;
                        ll A = s + t;
                        A %= p;
                        ll B = s - t + p;
                        B %= p;
                        func[j + k] = A;
                        func[j + k + b] = B;
                    }
                    now *= z;
                    now %= p;
                }
            }
            return;
        }
    }
    vector<ll> convolution_110(vector<ll> f, vector<ll> g)
    {
        if (!f_r)
        {
            r_r.resize(26);
            r_r_inv.resize(26);
            r_r[25] = 1087287097;
            drep(i, 25, 0)
            {
                r_r[i] = r_r[i + 1] * r_r[i + 1];
                r_r[i] %= R;
            }
            rep(i, 0, 26)
            {
                r_r_inv[i] = mod_inv(r_r[i], R);
            }
            f_r = true;
        }
        ll n = 1;
        ll m = f.size() + g.size() - 1;
        while (n <= m)
        {

            n *= 2;
        }
        f.resize(n);
        g.resize(n);
        assert(f.size() != 0 && g.size() != 0);
        vector<ll> nf, ng;
        rep(i, 0, n)
        {
            nf.push_back(f[i]);
            ng.push_back(g[i]);
        }
        nft_int(nf, false, R);
        nft_int(ng, false, R);
        vector<ll> inv(n);
        rep(i, 0, n)
        {
            inv[i] = nf[i] * ng[i];
            inv[i] %= R;
        }
        nft_int(inv, true, R);
        vector<ll> ret(n);
        ll n_inv = mod_inv(n, R);
        rep(i, 0, n)
        {
            ret[i] = inv[i] * n_inv;
            ret[i] %= R;
        }
        ret.resize(m);
        return ret;
    }

public:
    vector<complex<ld>> convolution(vector<complex<ld>> f, vector<complex<ld>> g)
    {
        ll n = 1;
        ll m = f.size() + g.size() - 1;
        while (n < m)
        {
            n *= 2;
        }
        f.resize(n);
        g.resize(n);
        assert(f.size() != 0 && g.size() != 0);
        vector<complex<ld>> nf, ng;
        rep(i, 0, n)
        {
            nf.push_back(f[i]);
            ng.push_back(g[i]);
        }
        dft(nf, false),
            dft(ng, false);
        vector<complex<ld>> inv(n);
        rep(i, 0, n)
        {
            inv[i] = nf[i] * ng[i];
        }
        dft(inv, true);
        vector<complex<ld>> ret(n);
        rep(i, 0, n)
        {
            ret[i] = (inv[i].real()) / (ld)n;
        }
        ret.resize(m);
        return ret;
    }
    vector<ll> convolution_998(vector<ll> f, vector<ll> g)
    {
        if (!f_p)
        {
            r_p.resize(24);
            r_p_inv.resize(24);
            r_p[23] = 15311432;
            drep(i, 23, 0)
            {
                r_p[i] = r_p[i + 1] * r_p[i + 1];
                r_p[i] %= P;
            }
            rep(i, 0, 24)
            {
                r_p_inv[i] = mod_inv(r_p[i], P);
            }
            f_p = true;
        }
        ll n = 1;
        ll m = f.size() + g.size() - 1;
        while (n <= m)
        {
            n *= 2;
        }
        f.resize(n);
        g.resize(n);
        assert(f.size() != 0 && g.size() != 0);
        vector<ll> nf, ng;
        rep(i, 0, n)
        {
            nf.push_back(f[i]);
            ng.push_back(g[i]);
        }
        nft_int(nf, false, P);
        nft_int(ng, false, P);
        vector<ll> inv(n);
        rep(i, 0, n)
        {
            inv[i] = nf[i] * ng[i];
            inv[i] %= P;
        }
        nft_int(inv, true, P);
        vector<ll> ret(n);
        ll n_inv = mod_inv(n, P);
        rep(i, 0, n)
        {
            ret[i] = inv[i] * n_inv;
            ret[i] %= P;
        }
        ret.resize(m);
        return ret;
    }
    /*
    vector<ll> convolution_ll(vector<ll> f, vector<ll> g)
    {
        vector<ll> a = convolution_110(f, g);
        vector<ll> b = convolution_998(f, g);
        Num N;
        vector<ll> ret;
        rep(i, 0, a.size())
        {
            ll x = N.CRT(a[i], R, b[i], P);
            ret.push_back(x);
        }
        return ret;
    }
        */
};
vector<bool> flg;
vector<vector<int>> G;
ll mod = 998244353;
FastFourierTransform FFT;
vector<ll> f(int rt)
{
    vector<ll> s(1, 1);
    vector<ll> ans1(1, 1);
    vector<ll> ans2(1, 1);
    rep(i, 0, G[rt].size())
    {
        vector<ll> d(1, 0);
        function<void(int, int, int)> dfs = [&](int u, int prev, int depth)
        {
            if (depth >= (int)d.size())
            {
                d.push_back(1);
            }
            else
            {
                d[depth]++;
            }
            for (auto v : G[u])
            {
                if (v != prev && !flg[v])
                {
                    dfs(v, u, depth + 1);
                }
            }
        };
        if (!flg[G[rt][i]])
        {
            dfs(G[rt][i], rt, 1);
        }
        vector<ll> ar = FFT.convolution_998(d, d);
        rep(i, 1, d.size())
        {
            if (ar.size() <= 2 * i)
            {
                ar.resize(2 * i + 1);
            }
            ar[2 * i] += mod - d[i];
            ar[2 * i] %= mod;
            if (s.size() <= i)
            {
                s.resize(i + 1);
            }
            s[i] += d[i];
            s[i] %= mod;
        }
        rep(i, 1, ar.size())
        {
            ar[i] *= 499122177;
            ar[i] %= mod;
            if (ans1.size() <= i)
            {
                ans1.resize(i + 1);
            }
            ans1[i] += ar[i];
            ans1[i] %= mod;
        }
    }
    ans2 = FFT.convolution_998(s, s);
    rep(i, 1, ans2.size())
    {
        if (i % 2 == 0 && (i / 2) < s.size())
        {
            ans2[i] += mod - s[i / 2];
            ans2[i] %= mod;
        }
        ans2[i] *= 499122177;
        ans2[i] %= mod;
        ans2[i] += mod - ans1[i];
        ans2[i] %= mod;
    }
    ans2[0] = 0;
    return ans2;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll n;
    cin >> n;
    G.resize(n);
    flg.resize(n);
    rep(i, 0, n - 1)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    vector<ll> ans(n);
    CentroidDecomposition CD(G);
    queue<ll> que;
    que.push(CD.G);
    while (!que.empty())
    {
        ll now = que.front();
        que.pop();
        vector<ll> a = f(now);
        flg[now] = true;
        rep(i, 0, a.size())
        {
            ans[i] += a[i];
            ans[i] %= mod;
        }
        rep(i, 0, CD.centroid_graph[now].size())
        {
            ll nxt = CD.centroid_graph[now][i];
            if (nxt != CD.centroid_graph_belong[now])
            {
                que.push(nxt);
            }
        }
    }
    Num N;
    N.nCrmod_init(2 * n, mod);
    vector<ll> x(n - 1), y(n - 1);
    rep(i, 0, n - 1)
    {
        x[i] = ans[n - 1 - i] * N.fac(n - 2 - i, mod);
        x[i] %= mod;
        y[i] = N.inv(N.fac(i, mod), mod);
    }
    vector<ll> ans2 = FFT.convolution_998(x, y);
    rep(i, 0, n - 1)
    {
        ans2[i] *= N.inv(N.fac(n - i - 2, mod), mod);
        ans2[i] %= mod;
    }
    ans2.resize(n - 1);
    rev(ans2);
    rep(i, 0, n - 1)
    {
        cout << ans2[i] << endl;
    }
}
accuracy: 1
time_ms: 2550
memory_kb: 92220
final_rank: 13

code_snippet: #include "bits/stdc++.h"
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
#define rep(i, m, n) for (ll i = (ll)m; i < (ll)n; i++)
#define drep(i, m, n) for (ll i = m - 1; i >= n; i--)
#define Endl endl
#define all(a) a.begin(), a.end()
#define pr(i, j) make_pair(i, j)
#define isin(x, l, r) (l <= x && x < r)
#define chmin(a, b) a = min(a, b)
#define chmax(a, b) a = max(a, b)
#define srt(ar) sort(ar.begin(), ar.end())
#define rev(ar) reverse(ar.begin(), ar.end())
#define jge(f, s, t) cout << (f ? s : t) << endl
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#define printar(ar)             \
    do                          \
    {                           \
        for (auto dbg : ar)     \
        {                       \
            cout << dbg << " "; \
        }                       \
        cout << endl;           \
    } while (0)
const ll inf = 1e18;
const ld pi = 3.14159265358979;
const ld eps = 1e-9;
template <class T, ll n, ll idx = 0>
auto make_vec(const ll (&d)[n], const T &init) noexcept
{
    if constexpr (idx < n)
        return std::vector(d[idx], make_vec<T, n, idx + 1>(d, init));
    else
        return init;
}

template <class T, ll n>
auto make_vec(const ll (&d)[n]) noexcept
{
    return make_vec(d, T{});
}
//////////////// 以下を貼る ////////////////
template <class T>
size_t HashCombine(const size_t seed, const T &v)
{
    return seed ^ (std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
/* pair用 */
template <class T, class S>
struct std::hash<std::pair<T, S>>
{
    size_t operator()(const std::pair<T, S> &keyval) const noexcept
    {
        return HashCombine(std::hash<T>()(keyval.first), keyval.second);
    }
};

class CentroidDecomposition
{
private:
    void build_inside(vector<int> &lavels, vector<vector<int>> &g, int from)
    {
        int x = centroid(g);
        int r = lavels[x];
        /*
        lavels_each[r] = lavels;
        graph_each[r] = g;
        重いので使用不可！
        */
        if (from != -1)
        {
            centroid_graph[r].push_back(from);
            centroid_graph[from].push_back(r);
            centroid_graph_belong[r] = from;
        }
        else
        {
            G = r;
        }
        vector<int> visit_t(lavels.size(), -1);
        rep(i, 0, g[x].size())
        {
            int next = g[x][i];
            vector<int> lavels_new;
            vector<int> v_g;
            queue<pair<int, int>> bfs;
            bfs.push(pr(next, x));
            int t = 0;
            while (!bfs.empty())
            {
                int now = bfs.front().first;
                int prev = bfs.front().second;
                bfs.pop();
                lavels_new.push_back(lavels[now]);
                v_g.push_back(now);
                visit_t[now] = t;
                t++;
                for (auto v : g[now])
                {
                    if (v != prev)
                    {
                        bfs.push(pr(v, now));
                    }
                }
            }
            vector<vector<int>> g_new(lavels_new.size());
            bfs.push(pr(next, x));
            while (!bfs.empty())
            {
                int now = bfs.front().first;
                int prev = bfs.front().second;
                int nx = visit_t[now];
                bfs.pop();
                for (auto v : g[now])
                {
                    if (v != prev)
                    {
                        g_new[nx].push_back(visit_t[v]);
                        g_new[visit_t[v]].push_back(nx);
                        bfs.push(pr(v, now));
                    }
                }
            }
            build_inside(lavels_new, g_new, r);
        }
    }
    int centroid(vector<vector<int>> &g)
    {
        int N = g.size();
        vector<int> sz(N);
        vector<int> centroid;
        function<void(int, int)> dfs = [&](int u, int prev)
        {
            sz[u] = 1;
            bool is_centroid = true;
            for (auto v : g[u])
            {
                if (v != prev)
                {
                    dfs(v, u);
                    sz[u] += sz[v];
                    if (sz[v] > N / 2)
                    {
                        is_centroid = false;
                    }
                }
            }
            if (N - sz[u] > N / 2)
            {
                is_centroid = false;
            }
            if (is_centroid)
            {
                centroid.push_back(u);
            }
        };
        dfs(0, -1);
        return centroid[0];
    }

public:
    /*
        vector<vector<int>> lavels_each;        // graph_eachのラベル
        vector<vector<vector<int>>> graph_each; // 頂点iが重心(かつ根)となっているような木を返す
        重いので使用不可！
    */
    vector<vector<int>> centroid_graph; // 重心同士を結んだ木
    vector<int> centroid_graph_belong;  // 重心同士を結んだ木の、頂点iの親
    int G;                              // 元のグラフの重心
    void build(vector<vector<int>> &g)
    {
        int N = g.size();
        /*
        lavels_each.resize(N);
        graph_each.resize(N);
        */
        centroid_graph.resize(N);
        centroid_graph_belong.resize(N, -1);
        vector<int> lavels(N);
        rep(i, 0, N)
        {
            lavels[i] = i;
        }
        build_inside(lavels, g, -1);
    }
    void debug()
    {
        rep(i, 0, centroid_graph.size())
        {
            printar(centroid_graph[i]);
        }
    }
    CentroidDecomposition(vector<vector<int>> &g)
    {
        build(g);
    }
};

class Num
{
private:
    vector<ll> fac_mod_ar = {};
    vector<ll> mobius_ar = {};
    vector<bool> isprime_ar = {};
    vector<ll> base_2_ar = {};

public:
    // gcd(a,b)を返す
    ll gcd(ll a, ll b)
    {
        if (a == 0 || b == 0)
            return 0;
        if (b > a)
            swap(a, b);
        if (a % b == 0)
            return b;
        else
        {
            return gcd(b, a % b);
        }
    }
    // lcm(a,b)を返す
    ll lcm(ll a, ll b)
    {
        return b / gcd(a, b) * a;
    }
    // a^b (modp)を返す
    ll exp(ll a, ll b, ll p)
    {
        if (b == 0)
            return 1;
        ll l = log2((b));
        ll num = l + 1;
        // cout << num << endl;
        base_2_ar.resize(num);
        base_2_ar[0] = a;
        rep(i, 1, num)
        {
            base_2_ar[i] = base_2_ar[i - 1] * base_2_ar[i - 1];
            base_2_ar[i] %= p;
            // cout << base_2[i] << endl;
        }
        ll ret = 1;
        rep(i, 0, num)
        {
            // cout << (b >> i) % 2;
            if ((b >> i) % 2 == 1)
                ret *= base_2_ar[i];
            ret %= p;
        }
        return ret;
    }
    // ax+by=gcd(a,b)を満たすx,yを求める
    ll ax_by(ll a, ll b, ll &x, ll &y)
    {
        if (b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        ll d = ax_by(b, a % b, y, x);
        y -= a / b * x;
        return d;
    }
    // a(mod m1),b(modm2)なるxを求める 中国剰余定理
    ll CRT(ll a, ll m1, ll b, ll m2)
    {
        ll x, y;
        ax_by(m1, m2, x, y);
        y *= (a - b);
        x %= m2;
        x *= (b - a);
        x %= m2;
        ll k = (m1 * x + a);
        k %= m1 * m2;
        k += m1 * m2;
        k %= m1 * m2;
        return k;
    }
    // mod pにおけるaの逆元を求める
    ll inv(ll a, ll p)
    {
        ll ret, b;
        ax_by(a, p, ret, b);
        ret %= p;
        ret += p;
        ret %= p;
        return ret;
    }

    // φ(n)を求める
    ll phi(ll n)
    {
        ll ret = n;
        for (ll i = 2; i * i <= n; i++)
        {
            if (n % i == 0)
            {
                while (n % i == 0)
                    n /= i;
                ret *= (i - 1);
                ret /= i;
            }
        }
        if (n != 1)
        {
            ret *= (n - 1);
            ret /= n;
        }
        return ret;
    }
    // 素数判定のための前計算 O(nloglogn)
    void isprime_init(ll n)
    {
        if (isprime_ar.size() >= n + 1)
            return;
        isprime_ar.resize(n + 1, true);
        isprime_ar[0] = false;
        isprime_ar[1] = false;
        for (ll i = 2; i <= n; i++)
        {
            if (isprime_ar[i])
            {
                for (ll j = 2 * i; j <= n; j += i)
                {
                    isprime_ar[j] = false;
                }
            }
        }
    }
    // nCrmodのための前計算 O(n)
    void nCrmod_init(ll n, ll p)
    {
        if (fac_mod_ar.size() >= n + 1)
            return;
        fac_mod_ar.resize(0);
        fac_mod_ar.resize(n + 1);
        fac_mod_ar[0] = 1;
        rep(i, 1, n + 1)
        {
            fac_mod_ar[i] = fac_mod_ar[i - 1] * i;
            fac_mod_ar[i] %= p;
        }
    }
    // メビウス関数のための前計算 O(nloglogn)
    void mobius_init(ll n)
    {
        if (mobius_ar.size() >= n + 1)
            return;
        mobius_ar.resize(n + 1, 1);
        isprime_init(n);
        mobius_ar[1] = 1;
        for (ll i = 2; i <= n; i++)
        {
            if (!isprime(i))
                continue;
            mobius_ar[i] = -1;
            for (ll j = 2 * i; j <= n; j += i)
            {
                if (j % (i * i) == 0)
                    mobius_ar[j] = 0;
                else
                    mobius_ar[j] *= -1;
            }
        }
    }
    // nの素数判定 前計算が必要
    bool isprime(ll n)
    {
        isprime_init(n);
        return isprime_ar[n];
    }
    // n! mod pを求める 前計算が必要
    ll fac(ll n, ll p)
    {
        nCrmod_init(n, p);
        return fac_mod_ar[n];
    }
    // nCr(mod p)を求める 前計算が必要
    ll nCrmod(ll n, ll r, ll p)
    {
        nCrmod_init(n, p);
        ll ret = 1;
        ret *= fac_mod_ar[n];
        ret %= p;
        ret *= inv(fac_mod_ar[r], p);
        ret %= p;
        ret *= inv(fac_mod_ar[n - r], p);
        ret %= p;
        return ret;
    }
    // μ(n)を求める　前計算が必要
    ll mobius(ll n)
    {
        mobius_init(n);
        return mobius_ar[n];
    }
};
////////////////////////////////////////////////

class FastFourierTransform
{
private:
    ll P = 998244353;
    ll R = 1107296257;
    vector<ll> r_p;
    vector<ll> r_r;
    vector<ll> r_p_inv;
    vector<ll> r_r_inv;
    bool f_p = false;
    bool f_r = false;
    ll mod_inv(ll n, ll p)
    {
        ll b = p, u = 1, v = 0;
        while (b)
        {
            ll t = n / b;
            n -= t * b;
            swap(n, b);
            u -= t * v;
            swap(u, v);
        }
        u %= p;
        if (u < 0)
            u += p;
        return u;
    }
    void dft(vector<complex<ld>> &func, bool isinv)
    {
        ll n = func.size();
        if (n == 1)
        {
            return;
        }
        else
        {
            vector<complex<ld>> a, b;
            rep(i, 0, n)
            {
                if (i % 2 == 0)
                {
                    a.push_back(func[i]);
                }
                else
                {
                    b.push_back(func[i]);
                }
            }
            dft(a, isinv);
            dft(b, isinv);
            complex<ld> now = 1;
            ld theta = (2.0 * acos(-1)) / n;
            if (isinv)
            {
                theta *= -1.0;
            }
            complex<ld> z = polar((ld)1.0, theta);
            rep(i, 0, n)
            {
                func[i] = a[i % (n / 2)] + now * b[i % (n / 2)];
                now *= z;
            }
            return;
        }
    }
    void nft_int(vector<ll> &func, bool isinv, ll p)
    {
        ll n = func.size();
        if (n == 1)
        {
            return;
        }
        else
        {
            ll x = log2(n);
            rep(i, 0, n)
            {
                ll j = 0;
                rep(k, 0, x)
                {
                    j |= ((i >> k) & 1LL) << (x - 1 - k);
                }
                if (i < j)
                {
                    swap(func[i], func[j]);
                }
            }
            rep(i, 0, x)
            {
                ll b = (1LL << i);
                ll now = 1;
                ll z = -1;
                if (p == P)
                {
                    z = r_p[i + 1];
                    if (isinv)
                    {
                        z = r_p_inv[i + 1];
                    }
                }
                else
                {
                    z = r_r[i + 1];
                    if (isinv)
                    {
                        z = r_r_inv[i + 1];
                    }
                }
                rep(j, 0, b)
                {
                    for (int k = 0; k < n; k += b * 2)
                    {
                        ll s = func[j + k];
                        ll t = func[j + k + b] * now;
                        t %= p;
                        ll A = s + t;
                        A %= p;
                        ll B = s - t + p;
                        B %= p;
                        func[j + k] = A;
                        func[j + k + b] = B;
                    }
                    now *= z;
                    now %= p;
                }
            }
            return;
        }
    }
    vector<ll> convolution_110(vector<ll> f, vector<ll> g)
    {
        if (!f_r)
        {
            r_r.resize(26);
            r_r_inv.resize(26);
            r_r[25] = 1087287097;
            drep(i, 25, 0)
            {
                r_r[i] = r_r[i + 1] * r_r[i + 1];
                r_r[i] %= R;
            }
            rep(i, 0, 26)
            {
                r_r_inv[i] = mod_inv(r_r[i], R);
            }
            f_r = true;
        }
        ll n = 1;
        ll m = f.size() + g.size() - 1;
        while (n <= m)
        {

            n *= 2;
        }
        f.resize(n);
        g.resize(n);
        assert(f.size() != 0 && g.size() != 0);
        vector<ll> nf, ng;
        rep(i, 0, n)
        {
            nf.push_back(f[i]);
            ng.push_back(g[i]);
        }
        nft_int(nf, false, R);
        nft_int(ng, false, R);
        vector<ll> inv(n);
        rep(i, 0, n)
        {
            inv[i] = nf[i] * ng[i];
            inv[i] %= R;
        }
        nft_int(inv, true, R);
        vector<ll> ret(n);
        ll n_inv = mod_inv(n, R);
        rep(i, 0, n)
        {
            ret[i] = inv[i] * n_inv;
            ret[i] %= R;
        }
        ret.resize(m);
        return ret;
    }

public:
    vector<complex<ld>> convolution(vector<complex<ld>> f, vector<complex<ld>> g)
    {
        ll n = 1;
        ll m = f.size() + g.size() - 1;
        while (n < m)
        {
            n *= 2;
        }
        f.resize(n);
        g.resize(n);
        assert(f.size() != 0 && g.size() != 0);
        vector<complex<ld>> nf, ng;
        rep(i, 0, n)
        {
            nf.push_back(f[i]);
            ng.push_back(g[i]);
        }
        dft(nf, false),
            dft(ng, false);
        vector<complex<ld>> inv(n);
        rep(i, 0, n)
        {
            inv[i] = nf[i] * ng[i];
        }
        dft(inv, true);
        vector<complex<ld>> ret(n);
        rep(i, 0, n)
        {
            ret[i] = (inv[i].real()) / (ld)n;
        }
        ret.resize(m);
        return ret;
    }
    vector<ll> convolution_998(vector<ll> f, vector<ll> g)
    {
        if (!f_p)
        {
            r_p.resize(24);
            r_p_inv.resize(24);
            r_p[23] = 15311432;
            drep(i, 23, 0)
            {
                r_p[i] = r_p[i + 1] * r_p[i + 1];
                r_p[i] %= P;
            }
            rep(i, 0, 24)
            {
                r_p_inv[i] = mod_inv(r_p[i], P);
            }
            f_p = true;
        }
        ll n = 1;
        ll m = f.size() + g.size() - 1;
        while (n <= m)
        {
            n *= 2;
        }
        f.resize(n);
        g.resize(n);
        assert(f.size() != 0 && g.size() != 0);
        vector<ll> nf, ng;
        rep(i, 0, n)
        {
            nf.push_back(f[i]);
            ng.push_back(g[i]);
        }
        nft_int(nf, false, P);
        nft_int(ng, false, P);
        vector<ll> inv(n);
        rep(i, 0, n)
        {
            inv[i] = nf[i] * ng[i];
            inv[i] %= P;
        }
        nft_int(inv, true, P);
        vector<ll> ret(n);
        ll n_inv = mod_inv(n, P);
        rep(i, 0, n)
        {
            ret[i] = inv[i] * n_inv;
            ret[i] %= P;
        }
        ret.resize(m);
        return ret;
    }
    /*
    vector<ll> convolution_ll(vector<ll> f, vector<ll> g)
    {
        vector<ll> a = convolution_110(f, g);
        vector<ll> b = convolution_998(f, g);
        Num N;
        vector<ll> ret;
        rep(i, 0, a.size())
        {
            ll x = N.CRT(a[i], R, b[i], P);
            ret.push_back(x);
        }
        return ret;
    }
        */
};
vector<bool> flg;
vector<vector<int>> G;
ll mod = 998244353;
FastFourierTransform FFT;
vector<ll> f(int rt)
{
    vector<ll> s(1, 1);
    vector<ll> ans1(1, 1);
    vector<ll> ans2(1, 1);
    rep(i, 0, G[rt].size())
    {
        vector<ll> d(1, 0);
        function<void(int, int, int)> dfs = [&](int u, int prev, int depth)
        {
            if (depth >= (int)d.size())
            {
                d.push_back(1);
            }
            else
            {
                d[depth]++;
            }
            for (auto v : G[u])
            {
                if (v != prev && !flg[v])
                {
                    dfs(v, u, depth + 1);
                }
            }
        };
        if (!flg[G[rt][i]])
        {
            dfs(G[rt][i], rt, 1);
        }
        vector<ll> ar = FFT.convolution_998(d, d);
        rep(i, 1, d.size())
        {
            if (ar.size() <= 2 * i)
            {
                ar.resize(2 * i + 1);
            }
            ar[2 * i] -= d[i];
            if (s.size() <= i)
            {
                s.resize(i + 1);
            }
            s[i] += d[i];
        }
        rep(i, 1, ar.size())
        {
            ar[i] /= 2;
            if (ans1.size() <= i)
            {
                ans1.resize(i + 1);
            }
            ans1[i] += ar[i];
        }
    }
    ans2 = FFT.convolution_998(s, s);
    rep(i, 1, ans2.size())
    {
        if (i % 2 == 0 && (i / 2) < s.size())
        {
            ans2[i] -= s[i / 2];
            ans2[i] %= mod;
            ans2[i] += mod;
            ans2[i] %= mod;
        }
        ans2[i] *= 499122177;
        ans2[i] -= ans1[i];
        ans2[i] %= mod;
    }
    ans2[0] = 0;
    return ans2;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll n;
    cin >> n;
    G.resize(n);
    flg.resize(n);
    rep(i, 0, n - 1)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    vector<ll> ans(n);
    CentroidDecomposition CD(G);
    queue<ll> que;
    que.push(CD.G);
    while (!que.empty())
    {
        ll now = que.front();
        que.pop();
        vector<ll> a = f(now);
        flg[now] = true;
        rep(i, 0, a.size())
        {
            ans[i] += a[i];
            ans[i] %= mod;
        }
        rep(i, 0, CD.centroid_graph[now].size())
        {
            ll nxt = CD.centroid_graph[now][i];
            if (nxt != CD.centroid_graph_belong[now])
            {
                que.push(nxt);
            }
        }
    }
    Num N;
    N.nCrmod_init(2 * n, mod);
    vector<ll> x(n - 1), y(n - 1);
    rep(i, 0, n - 1)
    {
        x[i] = ans[n - 1 - i] * N.fac(n - 2 - i, mod);
        x[i] %= mod;
        y[i] = N.inv(N.fac(i, mod), mod);
    }
    vector<ll> ans2 = FFT.convolution_998(x, y);
    rep(i, 0, n - 1)
    {
        ans2[i] *= N.inv(N.fac(n - i - 2, mod), mod);
        ans2[i] %= mod;
    }
    ans2.resize(n - 1);
    rev(ans2);
    rep(i, 0, n - 1)
    {
        cout << ans2[i] << endl;
    }
}
accuracy: 0.9523809523809523
time_ms: 2520
memory_kb: 92220
final_rank: 15

code_snippet: #include "bits/stdc++.h"
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
#define rep(i, m, n) for (ll i = (ll)m; i < (ll)n; i++)
#define drep(i, m, n) for (ll i = m - 1; i >= n; i--)
#define Endl endl
#define all(a) a.begin(), a.end()
#define pr(i, j) make_pair(i, j)
#define isin(x, l, r) (l <= x && x < r)
#define chmin(a, b) a = min(a, b)
#define chmax(a, b) a = max(a, b)
#define srt(ar) sort(ar.begin(), ar.end())
#define rev(ar) reverse(ar.begin(), ar.end())
#define jge(f, s, t) cout << (f ? s : t) << endl
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#define printar(ar)             \
    do                          \
    {                           \
        for (auto dbg : ar)     \
        {                       \
            cout << dbg << " "; \
        }                       \
        cout << endl;           \
    } while (0)
const ll inf = 1e18;
const ld pi = 3.14159265358979;
const ld eps = 1e-9;
template <class T, ll n, ll idx = 0>
auto make_vec(const ll (&d)[n], const T &init) noexcept
{
    if constexpr (idx < n)
        return std::vector(d[idx], make_vec<T, n, idx + 1>(d, init));
    else
        return init;
}

template <class T, ll n>
auto make_vec(const ll (&d)[n]) noexcept
{
    return make_vec(d, T{});
}
//////////////// 以下を貼る ////////////////
template <class T>
size_t HashCombine(const size_t seed, const T &v)
{
    return seed ^ (std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
/* pair用 */
template <class T, class S>
struct std::hash<std::pair<T, S>>
{
    size_t operator()(const std::pair<T, S> &keyval) const noexcept
    {
        return HashCombine(std::hash<T>()(keyval.first), keyval.second);
    }
};

class CentroidDecomposition
{
private:
    void build_inside(vector<int> &lavels, vector<vector<int>> &g, int from)
    {
        int x = centroid(g);
        int r = lavels[x];
        /*
        lavels_each[r] = lavels;
        graph_each[r] = g;
        重いので使用不可！
        */
        if (from != -1)
        {
            centroid_graph[r].push_back(from);
            centroid_graph[from].push_back(r);
            centroid_graph_belong[r] = from;
        }
        else
        {
            G = r;
        }
        vector<int> visit_t(lavels.size(), -1);
        rep(i, 0, g[x].size())
        {
            int next = g[x][i];
            vector<int> lavels_new;
            vector<int> v_g;
            queue<pair<int, int>> bfs;
            bfs.push(pr(next, x));
            int t = 0;
            while (!bfs.empty())
            {
                int now = bfs.front().first;
                int prev = bfs.front().second;
                bfs.pop();
                lavels_new.push_back(lavels[now]);
                v_g.push_back(now);
                visit_t[now] = t;
                t++;
                for (auto v : g[now])
                {
                    if (v != prev)
                    {
                        bfs.push(pr(v, now));
                    }
                }
            }
            vector<vector<int>> g_new(lavels_new.size());
            bfs.push(pr(next, x));
            while (!bfs.empty())
            {
                int now = bfs.front().first;
                int prev = bfs.front().second;
                int nx = visit_t[now];
                bfs.pop();
                for (auto v : g[now])
                {
                    if (v != prev)
                    {
                        g_new[nx].push_back(visit_t[v]);
                        g_new[visit_t[v]].push_back(nx);
                        bfs.push(pr(v, now));
                    }
                }
            }
            build_inside(lavels_new, g_new, r);
        }
    }
    int centroid(vector<vector<int>> &g)
    {
        int N = g.size();
        vector<int> sz(N);
        vector<int> centroid;
        function<void(int, int)> dfs = [&](int u, int prev)
        {
            sz[u] = 1;
            bool is_centroid = true;
            for (auto v : g[u])
            {
                if (v != prev)
                {
                    dfs(v, u);
                    sz[u] += sz[v];
                    if (sz[v] > N / 2)
                    {
                        is_centroid = false;
                    }
                }
            }
            if (N - sz[u] > N / 2)
            {
                is_centroid = false;
            }
            if (is_centroid)
            {
                centroid.push_back(u);
            }
        };
        dfs(0, -1);
        return centroid[0];
    }

public:
    /*
        vector<vector<int>> lavels_each;        // graph_eachのラベル
        vector<vector<vector<int>>> graph_each; // 頂点iが重心(かつ根)となっているような木を返す
        重いので使用不可！
    */
    vector<vector<int>> centroid_graph; // 重心同士を結んだ木
    vector<int> centroid_graph_belong;  // 重心同士を結んだ木の、頂点iの親
    int G;                              // 元のグラフの重心
    void build(vector<vector<int>> &g)
    {
        int N = g.size();
        /*
        lavels_each.resize(N);
        graph_each.resize(N);
        */
        centroid_graph.resize(N);
        centroid_graph_belong.resize(N, -1);
        vector<int> lavels(N);
        rep(i, 0, N)
        {
            lavels[i] = i;
        }
        build_inside(lavels, g, -1);
    }
    void debug()
    {
        rep(i, 0, centroid_graph.size())
        {
            printar(centroid_graph[i]);
        }
    }
    CentroidDecomposition(vector<vector<int>> &g)
    {
        build(g);
    }
};


class Num
{
private:
    vector<ll> fac_mod_ar = {};
    vector<ll> mobius_ar = {};
    vector<bool> isprime_ar = {};
    vector<ll> base_2_ar = {};

public:
    // gcd(a,b)を返す
    ll gcd(ll a, ll b)
    {
        if (a == 0 || b == 0)
            return 0;
        if (b > a)
            swap(a, b);
        if (a % b == 0)
            return b;
        else
        {
            return gcd(b, a % b);
        }
    }
    // lcm(a,b)を返す
    ll lcm(ll a, ll b)
    {
        return b / gcd(a, b) * a;
    }
    // a^b (modp)を返す
    ll exp(ll a, ll b, ll p)
    {
        if (b == 0)
            return 1;
        ll l = log2((b));
        ll num = l + 1;
        // cout << num << endl;
        base_2_ar.resize(num);
        base_2_ar[0] = a;
        rep(i, 1, num)
        {
            base_2_ar[i] = base_2_ar[i - 1] * base_2_ar[i - 1];
            base_2_ar[i] %= p;
            // cout << base_2[i] << endl;
        }
        ll ret = 1;
        rep(i, 0, num)
        {
            // cout << (b >> i) % 2;
            if ((b >> i) % 2 == 1)
                ret *= base_2_ar[i];
            ret %= p;
        }
        return ret;
    }
    // ax+by=gcd(a,b)を満たすx,yを求める
    ll ax_by(ll a, ll b, ll &x, ll &y)
    {
        if (b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        ll d = ax_by(b, a % b, y, x);
        y -= a / b * x;
        return d;
    }
    // a(mod m1),b(modm2)なるxを求める 中国剰余定理
    ll CRT(ll a, ll m1, ll b, ll m2)
    {
        ll x, y;
        ax_by(m1, m2, x, y);
        y *= (a - b);
        x %= m2;
        x *= (b - a);
        x %= m2;
        ll k = (m1 * x + a);
        k %= m1 * m2;
        k += m1 * m2;
        k %= m1 * m2;
        return k;
    }
    // mod pにおけるaの逆元を求める
    ll inv(ll a, ll p)
    {
        ll ret, b;
        ax_by(a, p, ret, b);
        ret %= p;
        ret += p;
        ret %= p;
        return ret;
    }

    // φ(n)を求める
    ll phi(ll n)
    {
        ll ret = n;
        for (ll i = 2; i * i <= n; i++)
        {
            if (n % i == 0)
            {
                while (n % i == 0)
                    n /= i;
                ret *= (i - 1);
                ret /= i;
            }
        }
        if (n != 1)
        {
            ret *= (n - 1);
            ret /= n;
        }
        return ret;
    }
    // 素数判定のための前計算 O(nloglogn)
    void isprime_init(ll n)
    {
        if (isprime_ar.size() >= n + 1)
            return;
        isprime_ar.resize(n + 1, true);
        isprime_ar[0] = false;
        isprime_ar[1] = false;
        for (ll i = 2; i <= n; i++)
        {
            if (isprime_ar[i])
            {
                for (ll j = 2 * i; j <= n; j += i)
                {
                    isprime_ar[j] = false;
                }
            }
        }
    }
    // nCrmodのための前計算 O(n)
    void nCrmod_init(ll n, ll p)
    {
        if (fac_mod_ar.size() >= n + 1)
            return;
        fac_mod_ar.resize(0);
        fac_mod_ar.resize(n + 1);
        fac_mod_ar[0] = 1;
        rep(i, 1, n + 1)
        {
            fac_mod_ar[i] = fac_mod_ar[i - 1] * i;
            fac_mod_ar[i] %= p;
        }
    }
    // メビウス関数のための前計算 O(nloglogn)
    void mobius_init(ll n)
    {
        if (mobius_ar.size() >= n + 1)
            return;
        mobius_ar.resize(n + 1, 1);
        isprime_init(n);
        mobius_ar[1] = 1;
        for (ll i = 2; i <= n; i++)
        {
            if (!isprime(i))
                continue;
            mobius_ar[i] = -1;
            for (ll j = 2 * i; j <= n; j += i)
            {
                if (j % (i * i) == 0)
                    mobius_ar[j] = 0;
                else
                    mobius_ar[j] *= -1;
            }
        }
    }
    // nの素数判定 前計算が必要
    bool isprime(ll n)
    {
        isprime_init(n);
        return isprime_ar[n];
    }
    // n! mod pを求める 前計算が必要
    ll fac(ll n, ll p)
    {
        nCrmod_init(n, p);
        return fac_mod_ar[n];
    }
    // nCr(mod p)を求める 前計算が必要
    ll nCrmod(ll n, ll r, ll p)
    {
        nCrmod_init(n, p);
        ll ret = 1;
        ret *= fac_mod_ar[n];
        ret %= p;
        ret *= inv(fac_mod_ar[r], p);
        ret %= p;
        ret *= inv(fac_mod_ar[n - r], p);
        ret %= p;
        return ret;
    }
    // μ(n)を求める　前計算が必要
    ll mobius(ll n)
    {
        mobius_init(n);
        return mobius_ar[n];
    }
};
////////////////////////////////////////////////

class FastFourierTransform
{
private:
    ll P = 998244353;
    ll R = 1107296257;
    vector<ll> r_p;
    vector<ll> r_r;
    vector<ll> r_p_inv;
    vector<ll> r_r_inv;
    bool f_p = false;
    bool f_r = false;
    ll mod_inv(ll n, ll p)
    {
        ll b = p, u = 1, v = 0;
        while (b)
        {
            ll t = n / b;
            n -= t * b;
            swap(n, b);
            u -= t * v;
            swap(u, v);
        }
        u %= p;
        if (u < 0)
            u += p;
        return u;
    }
    void dft(vector<complex<ld>> &func, bool isinv)
    {
        ll n = func.size();
        if (n == 1)
        {
            return;
        }
        else
        {
            vector<complex<ld>> a, b;
            rep(i, 0, n)
            {
                if (i % 2 == 0)
                {
                    a.push_back(func[i]);
                }
                else
                {
                    b.push_back(func[i]);
                }
            }
            dft(a, isinv);
            dft(b, isinv);
            complex<ld> now = 1;
            ld theta = (2.0 * acos(-1)) / n;
            if (isinv)
            {
                theta *= -1.0;
            }
            complex<ld> z = polar((ld)1.0, theta);
            rep(i, 0, n)
            {
                func[i] = a[i % (n / 2)] + now * b[i % (n / 2)];
                now *= z;
            }
            return;
        }
    }
    void nft_int(vector<ll> &func, bool isinv, ll p)
    {
        ll n = func.size();
        if (n == 1)
        {
            return;
        }
        else
        {
            ll x = log2(n);
            rep(i, 0, n)
            {
                ll j = 0;
                rep(k, 0, x)
                {
                    j |= ((i >> k) & 1LL) << (x - 1 - k);
                }
                if (i < j)
                {
                    swap(func[i], func[j]);
                }
            }
            rep(i, 0, x)
            {
                ll b = (1LL << i);
                ll now = 1;
                ll z = -1;
                if (p == P)
                {
                    z = r_p[i + 1];
                    if (isinv)
                    {
                        z = r_p_inv[i + 1];
                    }
                }
                else
                {
                    z = r_r[i + 1];
                    if (isinv)
                    {
                        z = r_r_inv[i + 1];
                    }
                }
                rep(j, 0, b)
                {
                    for (int k = 0; k < n; k += b * 2)
                    {
                        ll s = func[j + k];
                        ll t = func[j + k + b] * now;
                        t %= p;
                        ll A = s + t;
                        A %= p;
                        ll B = s - t + p;
                        B %= p;
                        func[j + k] = A;
                        func[j + k + b] = B;
                    }
                    now *= z;
                    now %= p;
                }
            }
            return;
        }
    }
    vector<ll> convolution_110(vector<ll> f, vector<ll> g)
    {
        if (!f_r)
        {
            r_r.resize(26);
            r_r_inv.resize(26);
            r_r[25] = 1087287097;
            drep(i, 25, 0)
            {
                r_r[i] = r_r[i + 1] * r_r[i + 1];
                r_r[i] %= R;
            }
            rep(i, 0, 26)
            {
                r_r_inv[i] = mod_inv(r_r[i], R);
            }
            f_r = true;
        }
        ll n = 1;
        ll m = f.size() + g.size() - 1;
        while (n <= m)
        {

            n *= 2;
        }
        f.resize(n);
        g.resize(n);
        assert(f.size() != 0 && g.size() != 0);
        vector<ll> nf, ng;
        rep(i, 0, n)
        {
            nf.push_back(f[i]);
            ng.push_back(g[i]);
        }
        nft_int(nf, false, R);
        nft_int(ng, false, R);
        vector<ll> inv(n);
        rep(i, 0, n)
        {
            inv[i] = nf[i] * ng[i];
            inv[i] %= R;
        }
        nft_int(inv, true, R);
        vector<ll> ret(n);
        ll n_inv = mod_inv(n, R);
        rep(i, 0, n)
        {
            ret[i] = inv[i] * n_inv;
            ret[i] %= R;
        }
        ret.resize(m);
        return ret;
    }

public:
    vector<complex<ld>> convolution(vector<complex<ld>> f, vector<complex<ld>> g)
    {
        ll n = 1;
        ll m = f.size() + g.size() - 1;
        while (n < m)
        {
            n *= 2;
        }
        f.resize(n);
        g.resize(n);
        assert(f.size() != 0 && g.size() != 0);
        vector<complex<ld>> nf, ng;
        rep(i, 0, n)
        {
            nf.push_back(f[i]);
            ng.push_back(g[i]);
        }
        dft(nf, false),
            dft(ng, false);
        vector<complex<ld>> inv(n);
        rep(i, 0, n)
        {
            inv[i] = nf[i] * ng[i];
        }
        dft(inv, true);
        vector<complex<ld>> ret(n);
        rep(i, 0, n)
        {
            ret[i] = (inv[i].real()) / (ld)n;
        }
        ret.resize(m);
        return ret;
    }
    vector<ll> convolution_998(vector<ll> f, vector<ll> g)
    {
        if (!f_p)
        {
            r_p.resize(24);
            r_p_inv.resize(24);
            r_p[23] = 15311432;
            drep(i, 23, 0)
            {
                r_p[i] = r_p[i + 1] * r_p[i + 1];
                r_p[i] %= P;
            }
            rep(i, 0, 24)
            {
                r_p_inv[i] = mod_inv(r_p[i], P);
            }
            f_p = true;
        }
        ll n = 1;
        ll m = f.size() + g.size() - 1;
        while (n <= m)
        {
            n *= 2;
        }
        f.resize(n);
        g.resize(n);
        assert(f.size() != 0 && g.size() != 0);
        vector<ll> nf, ng;
        rep(i, 0, n)
        {
            nf.push_back(f[i]);
            ng.push_back(g[i]);
        }
        nft_int(nf, false, P);
        nft_int(ng, false, P);
        vector<ll> inv(n);
        rep(i, 0, n)
        {
            inv[i] = nf[i] * ng[i];
            inv[i] %= P;
        }
        nft_int(inv, true, P);
        vector<ll> ret(n);
        ll n_inv = mod_inv(n, P);
        rep(i, 0, n)
        {
            ret[i] = inv[i] * n_inv;
            ret[i] %= P;
        }
        ret.resize(m);
        return ret;
    }
    /*
    vector<ll> convolution_ll(vector<ll> f, vector<ll> g)
    {
        vector<ll> a = convolution_110(f, g);
        vector<ll> b = convolution_998(f, g);
        Num N;
        vector<ll> ret;
        rep(i, 0, a.size())
        {
            ll x = N.CRT(a[i], R, b[i], P);
            ret.push_back(x);
        }
        return ret;
    }
        */
};
vector<bool> flg;
vector<vector<int>> G;
ll mod = 998244353;
FastFourierTransform FFT;
vector<ll> f(int rt)
{
    vector<ll> s(1, 1);
    vector<ll> ans1(1, 1);
    vector<ll> ans2(1, 1);
    rep(i, 0, G[rt].size())
    {
        vector<ll> d(1, 0);
        function<void(int, int, int)> dfs = [&](int u, int prev, int depth)
        {
            if (depth >= (int)d.size())
            {
                d.push_back(1);
            }
            else
            {
                d[depth]++;
            }
            for (auto v : G[u])
            {
                if (v != prev && !flg[v])
                {
                    dfs(v, u, depth + 1);
                }
            }
        };
        if (!flg[G[rt][i]])
        {
            dfs(G[rt][i], rt, 1);
        }
        vector<ll> ar = FFT.convolution_998(d, d);
        rep(i, 1, d.size())
        {
            if (ar.size() <= 2 * i)
            {
                ar.resize(2 * i + 1);
            }
            ar[2 * i] -= d[i];
            if (s.size() <= i)
            {
                s.resize(i + 1);
            }
            s[i] += d[i];
        }
        rep(i, 1, ar.size())
        {
            ar[i] /= 2;
            if (ans1.size() <= i)
            {
                ans1.resize(i + 1);
            }
            ans1[i] += ar[i];
        }
    }
    ans2 = FFT.convolution_998(s, s);
    rep(i, 1, ans2.size())
    {
        if (i % 2 == 0 && (i / 2) < s.size())
        {
            ans2[i] -= s[i / 2];
        }
        ans2[i] /= 2;
        ans2[i] -= ans1[i];
    }
    ans2[0] = 0;
    return ans2;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll n;
    cin >> n;
    G.resize(n);
    flg.resize(n);
    rep(i, 0, n - 1)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    vector<ll> ans(n);
    CentroidDecomposition CD(G);
    queue<ll> que;
    que.push(CD.G);
    while (!que.empty())
    {
        ll now = que.front();
        que.pop();
        vector<ll> a = f(now);
        flg[now] = true;
        rep(i, 0, a.size())
        {
            ans[i] += a[i];
        }
        rep(i, 0, CD.centroid_graph[now].size())
        {
            ll nxt = CD.centroid_graph[now][i];
            if (nxt != CD.centroid_graph_belong[now])
            {
                que.push(nxt);
            }
        }
    }
    Num N;
    N.nCrmod_init(2 * n, mod);
    vector<ll> x(n - 1), y(n - 1);
    rep(i, 0, n - 1)
    {
        x[i] = ans[n - 1 - i] * N.fac(n - 2 - i, mod);
        x[i] %= mod;
        y[i] = N.inv(N.fac(i, mod), mod);
    }
    vector<ll> ans2 = FFT.convolution_998(x, y);
    rep(i, 0, n - 1)
    {
        ans2[i] *= N.inv(N.fac(n - i - 2, mod), mod);
        ans2[i] %= mod;
    }
    ans2.resize(n - 1);
    rev(ans2);
    rep(i, 0, n - 1)
    {
        cout << ans2[i] << endl;
    }
}
accuracy: 0.9523809523809523
time_ms: 2510
memory_kb: 92232
final_rank: 14

code_snippet: #include "bits/stdc++.h"
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
#define rep(i, m, n) for (ll i = (ll)m; i < (ll)n; i++)
#define drep(i, m, n) for (ll i = m - 1; i >= n; i--)
#define Endl endl
#define all(a) a.begin(), a.end()
#define pr(i, j) make_pair(i, j)
#define isin(x, l, r) (l <= x && x < r)
#define chmin(a, b) a = min(a, b)
#define chmax(a, b) a = max(a, b)
#define srt(ar) sort(ar.begin(), ar.end())
#define rev(ar) reverse(ar.begin(), ar.end())
#define jge(f, s, t) cout << (f ? s : t) << endl
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#define printar(ar)             \
    do                          \
    {                           \
        for (auto dbg : ar)     \
        {                       \
            cout << dbg << " "; \
        }                       \
        cout << endl;           \
    } while (0)
const ll inf = 1e18;
const ld pi = 3.14159265358979;
const ld eps = 1e-9;
template <class T, ll n, ll idx = 0>
auto make_vec(const ll (&d)[n], const T &init) noexcept
{
    if constexpr (idx < n)
        return std::vector(d[idx], make_vec<T, n, idx + 1>(d, init));
    else
        return init;
}

template <class T, ll n>
auto make_vec(const ll (&d)[n]) noexcept
{
    return make_vec(d, T{});
}
//////////////// 以下を貼る ////////////////
template <class T>
size_t HashCombine(const size_t seed, const T &v)
{
    return seed ^ (std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
}
/* pair用 */
template <class T, class S>
struct std::hash<std::pair<T, S>>
{
    size_t operator()(const std::pair<T, S> &keyval) const noexcept
    {
        return HashCombine(std::hash<T>()(keyval.first), keyval.second);
    }
};

template <int mod>
struct ModInt
{
    int x;
    ModInt() : x(0) {}
    ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
    ModInt &operator+=(const ModInt &p)
    {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }
    ModInt &operator-=(const ModInt &p)
    {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }
    ModInt &operator*=(const ModInt &p)
    {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }
    ModInt &operator/=(const ModInt &p)
    {
        *this *= p.inverse();
        return *this;
    }
    ModInt operator-() const { return ModInt(-x); }
    ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
    ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
    ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
    ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
    bool operator==(const ModInt &p) const { return x == p.x; }
    bool operator!=(const ModInt &p) const { return x != p.x; }

    ModInt inverse() const
    {
        int a = x, b = mod, u = 1, v = 0, t;
        while (b > 0)
        {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return ModInt(u);
    }

    ModInt pow(int64_t n) const
    {
        ModInt ret(1), mul(x);
        while (n > 0)
        {
            if (n & 1)
                ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const ModInt &p)
    {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, ModInt &a)
    {
        int64_t t;
        is >> t;
        a = ModInt<mod>(t);
        return (is);
    }

    static int get_mod() { return mod; }
};
using mint = ModInt<998244353>;
using vm = vector<mint>;

struct NumberTheoreticTransform
{

    int mod = mint::get_mod();
    int mxb;
    mint r;

    NumberTheoreticTransform()
    {
        auto tmp = mod - 1;
        mxb = 0;
        while (tmp % 2 == 0)
            tmp >>= 1, mxb++;
        r = 2;
        while (r.pow((mod - 1) >> 1) == 1)
            r += 1;
        assert(r.pow(mod - 1) == 1);
        r = r.pow((mod - 1) >> mxb);
    }

    void ntt(vm &f, int lg, bool inv)
    {
        int sz = (int)f.size();
        for (int i = 0; i < sz; ++i)
        {
            int j = 0;
            for (int k = 0; k < lg; ++k)
            {
                j |= ((i >> k) & 1) << (lg - 1 - k);
            }
            if (i < j)
                swap(f[i], f[j]);
        }

        for (int i = 0; i < lg; ++i)
        {
            int b = 1 << i;
            mint now = 1;
            mint z = r.pow(1 << (mxb - 1 - i));
            if (inv)
                z = z.inverse();
            for (int j = 0; j < b; ++j)
            {
                for (int k = 0; k < sz; k += b * 2)
                {
                    mint s = f[j + k];
                    mint t = f[j + k + b] * now;
                    f[j + k] = s + t;
                    f[j + k + b] = s - t;
                }
                now *= z;
            }
        }
    }

    vm multiply(const vm &f, const vm &g)
    {
        vm nf, ng;
        size_t need = f.size() + g.size() - 1;
        int sz = 1, lg = 0;
        while (sz < (int)(f.size() + g.size()))
        {
            sz *= 2;
            ++lg;
        }
        nf.resize(sz), ng.resize(sz);
        for (int i = 0; i < (int)f.size(); ++i)
        {
            nf[i] = f[i];
        }
        for (int i = 0; i < (int)g.size(); ++i)
        {
            ng[i] = g[i];
        }
        ntt(nf, lg, 0);
        ntt(ng, lg, 0);
        for (int i = 0; i < sz; ++i)
        {
            nf[i] *= ng[i];
        }
        ntt(nf, lg, 1);
        vm ret(sz);
        mint inv_sz = mint(1) / sz;
        for (int i = 0; i < sz; ++i)
        {
            ret[i] = nf[i] * inv_sz;
        }
        ret.resize(need);
        return ret;
    }
} ntt;
class CentroidDecomposition
{
private:
    void build_inside(vector<int> &lavels, vector<vector<int>> &g, int from)
    {
        int x = centroid(g);
        int r = lavels[x];
        /*
        lavels_each[r] = lavels;
        graph_each[r] = g;
        重いので使用不可！
        */
        if (from != -1)
        {
            centroid_graph[r].push_back(from);
            centroid_graph[from].push_back(r);
            centroid_graph_belong[r] = from;
        }
        else
        {
            G = r;
        }
        vector<int> visit_t(lavels.size(), -1);
        rep(i, 0, g[x].size())
        {
            int next = g[x][i];
            vector<int> lavels_new;
            vector<int> v_g;
            queue<pair<int, int>> bfs;
            bfs.push(pr(next, x));
            int t = 0;
            while (!bfs.empty())
            {
                int now = bfs.front().first;
                int prev = bfs.front().second;
                bfs.pop();
                lavels_new.push_back(lavels[now]);
                v_g.push_back(now);
                visit_t[now] = t;
                t++;
                for (auto v : g[now])
                {
                    if (v != prev)
                    {
                        bfs.push(pr(v, now));
                    }
                }
            }
            vector<vector<int>> g_new(lavels_new.size());
            bfs.push(pr(next, x));
            while (!bfs.empty())
            {
                int now = bfs.front().first;
                int prev = bfs.front().second;
                int nx = visit_t[now];
                bfs.pop();
                for (auto v : g[now])
                {
                    if (v != prev)
                    {
                        g_new[nx].push_back(visit_t[v]);
                        g_new[visit_t[v]].push_back(nx);
                        bfs.push(pr(v, now));
                    }
                }
            }
            build_inside(lavels_new, g_new, r);
        }
    }
    int centroid(vector<vector<int>> &g)
    {
        int N = g.size();
        vector<int> sz(N);
        vector<int> centroid;
        function<void(int, int)> dfs = [&](int u, int prev)
        {
            sz[u] = 1;
            bool is_centroid = true;
            for (auto v : g[u])
            {
                if (v != prev)
                {
                    dfs(v, u);
                    sz[u] += sz[v];
                    if (sz[v] > N / 2)
                    {
                        is_centroid = false;
                    }
                }
            }
            if (N - sz[u] > N / 2)
            {
                is_centroid = false;
            }
            if (is_centroid)
            {
                centroid.push_back(u);
            }
        };
        dfs(0, -1);
        return centroid[0];
    }

public:
    /*
        vector<vector<int>> lavels_each;        // graph_eachのラベル
        vector<vector<vector<int>>> graph_each; // 頂点iが重心(かつ根)となっているような木を返す
        重いので使用不可！
    */
    vector<vector<int>> centroid_graph; // 重心同士を結んだ木
    vector<int> centroid_graph_belong;  // 重心同士を結んだ木の、頂点iの親
    int G;                              // 元のグラフの重心
    void build(vector<vector<int>> &g)
    {
        int N = g.size();
        /*
        lavels_each.resize(N);
        graph_each.resize(N);
        */
        centroid_graph.resize(N);
        centroid_graph_belong.resize(N, -1);
        vector<int> lavels(N);
        rep(i, 0, N)
        {
            lavels[i] = i;
        }
        build_inside(lavels, g, -1);
    }
    void debug()
    {
        rep(i, 0, centroid_graph.size())
        {
            printar(centroid_graph[i]);
        }
    }
    CentroidDecomposition(vector<vector<int>> &g)
    {
        build(g);
    }
};

vector<bool> flg;
vector<vector<int>> G;
ll mod = 998244353;
vector<mint> f(int rt)
{
    vector<mint> s(1, 1);
    vector<mint> ret(1, 1);
    rep(i, 0, G[rt].size())
    {
        if (flg[G[rt][i]])
        {
            continue;
        }
        vector<mint> d(1, 0);
        function<void(int, int, int)> dfs = [&](int u, int prev, int depth)
        {
            if (depth >= (int)d.size())
            {
                d.push_back(1);
            }
            else
            {
                d[depth] += 1;
            }
            for (auto v : G[u])
            {
                if (v != prev && !flg[v])
                {
                    dfs(v, u, depth + 1);
                }
            }
        };
        dfs(G[rt][i], rt, 1);
        vector<mint> ar = ntt.multiply(d, s);
        rep(i, 0, ar.size())
        {
            if (ret.size() <= i)
            {
                ret.resize(i + 1);
            }
            ret[i] += ar[i];
        }
        rep(i, 1, d.size())
        {
            if (s.size() <= i)
            {
                s.resize(i + 1);
            }
            s[i] += d[i];
        }
    }
    ret[0] = 1;
    return ret;
}
////////////////////////////////////////////////
// 整数関係のアルゴリズム
template <typename T>
class Num
{
private:
    vector<ll> fac_mod_ar = {};
    vector<ll> mobius_ar = {};
    vector<bool> isprime_ar = {};
    vector<ll> base_2_ar = {};

public:
    // gcd(a,b)を返す
    T gcd(T a, T b)
    {
        if (a == 0 || b == 0)
            return 0;
        if (b > a)
            swap(a, b);
        if (a % b == 0)
            return b;
        else
        {
            return gcd(b, a % b);
        }
    }
    // lcm(a,b)を返す
    T lcm(T a, T b)
    {
        return b / gcd(a, b) * a;
    }
    // a^b (modp)を返す
    T exp(T a, T b, T p)
    {
        if (b == 0)
            return 1;
        ll l = log2((b));
        ll num = l + 1;
        // cout << num << endl;
        base_2_ar.resize(num);
        base_2_ar[0] = a;
        rep(i, 1, num)
        {
            base_2_ar[i] = base_2_ar[i - 1] * base_2_ar[i - 1];
            base_2_ar[i] %= p;
            // cout << base_2[i] << endl;
        }
        ll ret = 1;
        rep(i, 0, num)
        {
            // cout << (b >> i) % 2;
            if ((b >> i) % 2 == 1)
                ret *= base_2_ar[i];
            ret %= p;
        }
        return ret;
    }
    // ax+by=gcd(a,b)を満たすx,yを求める
    T ax_by(T a, T b, T &x, T &y)
    {
        if (b == 0)
        {
            x = 1;
            y = 0;
            return a;
        }
        T d = ax_by(b, a % b, y, x);
        y -= a / b * x;
        return d;
    }
    // a(mod m1),b(modm2)なるxを求める 中国剰余定理
    T CRT(T a, T m1, T b, T m2)
    {
        T x, y;
        ax_by(m1, m2, x, y);
        y *= (a - b);
        x *= (b - a);
        T k = (m1 * x + a);
        k %= m1 * m2;
        k += m1 * m2;
        k %= m1 * m2;
        return k;
    }
    // mod pにおけるaの逆元を求める
    T inv(T a, T p)
    {
        T ret, b;
        ax_by(a, p, ret, b);
        ret %= p;
        ret += p;
        ret %= p;
        return ret;
    }

    // φ(n)を求める
    T phi(T n)
    {
        ll ret = n;
        for (ll i = 2; i * i <= n; i++)
        {
            if (n % i == 0)
            {
                while (n % i == 0)
                    n /= i;
                ret *= (i - 1);
                ret /= i;
            }
        }
        if (n != 1)
        {
            ret *= (n - 1);
            ret /= n;
        }
        return ret;
    }
    // 素数判定のための前計算 O(nloglogn)
    void isprime_init(ll n)
    {
        if (isprime_ar.size() >= n + 1)
            return;
        isprime_ar.resize(n + 1, true);
        isprime_ar[0] = false;
        isprime_ar[1] = false;
        for (ll i = 2; i <= n; i++)
        {
            if (isprime_ar[i])
            {
                for (ll j = 2 * i; j <= n; j += i)
                {
                    isprime_ar[j] = false;
                }
            }
        }
    }
    // nCrmodのための前計算 O(n)
    void nCrmod_init(T n, T p)
    {
        if (fac_mod_ar.size() >= n + 1)
            return;
        fac_mod_ar.resize(0);
        fac_mod_ar.resize(n + 1);
        fac_mod_ar[0] = 1;
        rep(i, 1, n + 1)
        {
            fac_mod_ar[i] = fac_mod_ar[i - 1] * i;
            fac_mod_ar[i] %= p;
        }
    }
    // メビウス関数のための前計算 O(nloglogn)
    void mobius_init(T n)
    {
        if (mobius_ar.size() >= n + 1)
            return;
        mobius_ar.resize(n + 1, 1);
        isprime_init(n);
        mobius_ar[1] = 1;
        for (ll i = 2; i <= n; i++)
        {
            if (!isprime(i))
                continue;
            mobius_ar[i] = -1;
            for (ll j = 2 * i; j <= n; j += i)
            {
                if (j % (i * i) == 0)
                    mobius_ar[j] = 0;
                else
                    mobius_ar[j] *= -1;
            }
        }
    }
    // nの素数判定 前計算が必要
    bool isprime(ll n)
    {
        isprime_init(n);
        return isprime_ar[n];
    }
    // n! mod pを求める 前計算が必要
    T fac(T n, T p)
    {
        nCrmod_init(n, p);
        return fac_mod_ar[n];
    }
    // nCr(mod p)を求める 前計算が必要
    T nCrmod(T n, T r, T p)
    {
        nCrmod_init(n, p);
        ll ret = 1;
        ret *= fac_mod_ar[n];
        ret %= p;
        ret *= inv(fac_mod_ar[r], p);
        ret %= p;
        ret *= inv(fac_mod_ar[n - r], p);
        ret %= p;
        return ret;
    }
    // μ(n)を求める　前計算が必要
    T mobius(T n)
    {
        mobius_init(n);
        return mobius_ar[n];
    }
};
////////////////////////////////////////////////
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll n;
    cin >> n;
    G.resize(n);
    flg.resize(n);
    rep(i, 0, n - 1)
    {
        ll a, b;
        cin >> a >> b;
        a--;
        b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    vector<mint> ans(n);
    CentroidDecomposition CD(G);
    queue<ll> que;
    que.push(CD.G);
    while (!que.empty())
    {
        ll now = que.front();
        que.pop();
        vector<mint> a = f(now);
        flg[now] = true;
        rep(i, 0, a.size())
        {
            ans[i] += a[i];
        }
        rep(i, 0, CD.centroid_graph[now].size())
        {
            ll nxt = CD.centroid_graph[now][i];
            if (nxt != CD.centroid_graph_belong[now])
            {
                que.push(nxt);
            }
        }
    }
    Num<ll> N;
    N.nCrmod_init(2 * n, mod);
    vector<mint> x(n - 1), y(n - 1);
    rep(i, 0, n - 1)
    {
        x[i] = ans[n - 1 - i] * N.fac(n - 2 - i, mod);
        y[i] = N.inv(N.fac(i, mod), mod);
    }
    vector<mint> ans2 = ntt.multiply(x, y);
    rep(i, 0, n - 1)
    {
        ans2[i] *= N.inv(N.fac(n - i - 2, mod), mod);
    }
    ans2.resize(n - 1);
    rev(ans2);
    rep(i, 0, n - 1)
    {
        cout << ans2[i] << endl;
    }
}
accuracy: 1
time_ms: 1130
memory_kb: 69664
final_rank: 9

code_snippet: #include <bits/stdc++.h>

namespace zawa {

using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;

using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;

using usize = std::size_t;

} // namespace zawa

namespace zawa {

void SetFastIO() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
}

void SetPrecision(u32 dig) {
    std::cout << std::fixed << std::setprecision(dig);
}

} // namespace zawa

using namespace zawa;

#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m`
    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned long long y = x * _m;
        return (unsigned int)(z - y + (z < y ? _m : 0));
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

}  // namespace internal

}  // namespace atcoder

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder



namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


#ifdef _MSC_VER
#include <intrin.h>
#endif

#if __cplusplus >= 202002L
#include <bit>
#endif

namespace atcoder {

namespace internal {

#if __cplusplus >= 202002L

using std::bit_ceil;

#else

// @return same with std::bit::bit_ceil
unsigned int bit_ceil(unsigned int n) {
    unsigned int x = 1;
    while (x < (unsigned int)(n)) x *= 2;
    return x;
}

#endif

// @param n `1 <= n`
// @return same with std::bit::countr_zero
int countr_zero(unsigned int n) {
#ifdef _MSC_VER
    unsigned long index;
    _BitScanForward(&index, n);
    return index;
#else
    return __builtin_ctz(n);
#endif
}

// @param n `1 <= n`
// @return same with std::bit::countr_zero
constexpr int countr_zero_constexpr(unsigned int n) {
    int x = 0;
    while (!(n & (1 << x))) x++;
    return x;
}

}  // namespace internal

}  // namespace atcoder



namespace atcoder {

namespace internal {

template <class mint,
          int g = internal::primitive_root<mint::mod()>,
          internal::is_static_modint_t<mint>* = nullptr>
struct fft_info {
    static constexpr int rank2 = countr_zero_constexpr(mint::mod() - 1);
    std::array<mint, rank2 + 1> root;   // root[i]^(2^i) == 1
    std::array<mint, rank2 + 1> iroot;  // root[i] * iroot[i] == 1

    std::array<mint, std::max(0, rank2 - 2 + 1)> rate2;
    std::array<mint, std::max(0, rank2 - 2 + 1)> irate2;

    std::array<mint, std::max(0, rank2 - 3 + 1)> rate3;
    std::array<mint, std::max(0, rank2 - 3 + 1)> irate3;

    fft_info() {
        root[rank2] = mint(g).pow((mint::mod() - 1) >> rank2);
        iroot[rank2] = root[rank2].inv();
        for (int i = rank2 - 1; i >= 0; i--) {
            root[i] = root[i + 1] * root[i + 1];
            iroot[i] = iroot[i + 1] * iroot[i + 1];
        }

        {
            mint prod = 1, iprod = 1;
            for (int i = 0; i <= rank2 - 2; i++) {
                rate2[i] = root[i + 2] * prod;
                irate2[i] = iroot[i + 2] * iprod;
                prod *= iroot[i + 2];
                iprod *= root[i + 2];
            }
        }
        {
            mint prod = 1, iprod = 1;
            for (int i = 0; i <= rank2 - 3; i++) {
                rate3[i] = root[i + 3] * prod;
                irate3[i] = iroot[i + 3] * iprod;
                prod *= iroot[i + 3];
                iprod *= root[i + 3];
            }
        }
    }
};

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly(std::vector<mint>& a) {
    int n = int(a.size());
    int h = internal::countr_zero((unsigned int)n);

    static const fft_info<mint> info;

    int len = 0;  // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed
    while (len < h) {
        if (h - len == 1) {
            int p = 1 << (h - len - 1);
            mint rot = 1;
            for (int s = 0; s < (1 << len); s++) {
                int offset = s << (h - len);
                for (int i = 0; i < p; i++) {
                    auto l = a[i + offset];
                    auto r = a[i + offset + p] * rot;
                    a[i + offset] = l + r;
                    a[i + offset + p] = l - r;
                }
                if (s + 1 != (1 << len))
                    rot *= info.rate2[countr_zero(~(unsigned int)(s))];
            }
            len++;
        } else {
            // 4-base
            int p = 1 << (h - len - 2);
            mint rot = 1, imag = info.root[2];
            for (int s = 0; s < (1 << len); s++) {
                mint rot2 = rot * rot;
                mint rot3 = rot2 * rot;
                int offset = s << (h - len);
                for (int i = 0; i < p; i++) {
                    auto mod2 = 1ULL * mint::mod() * mint::mod();
                    auto a0 = 1ULL * a[i + offset].val();
                    auto a1 = 1ULL * a[i + offset + p].val() * rot.val();
                    auto a2 = 1ULL * a[i + offset + 2 * p].val() * rot2.val();
                    auto a3 = 1ULL * a[i + offset + 3 * p].val() * rot3.val();
                    auto a1na3imag =
                        1ULL * mint(a1 + mod2 - a3).val() * imag.val();
                    auto na2 = mod2 - a2;
                    a[i + offset] = a0 + a2 + a1 + a3;
                    a[i + offset + 1 * p] = a0 + a2 + (2 * mod2 - (a1 + a3));
                    a[i + offset + 2 * p] = a0 + na2 + a1na3imag;
                    a[i + offset + 3 * p] = a0 + na2 + (mod2 - a1na3imag);
                }
                if (s + 1 != (1 << len))
                    rot *= info.rate3[countr_zero(~(unsigned int)(s))];
            }
            len += 2;
        }
    }
}

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly_inv(std::vector<mint>& a) {
    int n = int(a.size());
    int h = internal::countr_zero((unsigned int)n);

    static const fft_info<mint> info;

    int len = h;  // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed
    while (len) {
        if (len == 1) {
            int p = 1 << (h - len);
            mint irot = 1;
            for (int s = 0; s < (1 << (len - 1)); s++) {
                int offset = s << (h - len + 1);
                for (int i = 0; i < p; i++) {
                    auto l = a[i + offset];
                    auto r = a[i + offset + p];
                    a[i + offset] = l + r;
                    a[i + offset + p] =
                        (unsigned long long)(mint::mod() + l.val() - r.val()) *
                        irot.val();
                    ;
                }
                if (s + 1 != (1 << (len - 1)))
                    irot *= info.irate2[countr_zero(~(unsigned int)(s))];
            }
            len--;
        } else {
            // 4-base
            int p = 1 << (h - len);
            mint irot = 1, iimag = info.iroot[2];
            for (int s = 0; s < (1 << (len - 2)); s++) {
                mint irot2 = irot * irot;
                mint irot3 = irot2 * irot;
                int offset = s << (h - len + 2);
                for (int i = 0; i < p; i++) {
                    auto a0 = 1ULL * a[i + offset + 0 * p].val();
                    auto a1 = 1ULL * a[i + offset + 1 * p].val();
                    auto a2 = 1ULL * a[i + offset + 2 * p].val();
                    auto a3 = 1ULL * a[i + offset + 3 * p].val();

                    auto a2na3iimag =
                        1ULL *
                        mint((mint::mod() + a2 - a3) * iimag.val()).val();

                    a[i + offset] = a0 + a1 + a2 + a3;
                    a[i + offset + 1 * p] =
                        (a0 + (mint::mod() - a1) + a2na3iimag) * irot.val();
                    a[i + offset + 2 * p] =
                        (a0 + a1 + (mint::mod() - a2) + (mint::mod() - a3)) *
                        irot2.val();
                    a[i + offset + 3 * p] =
                        (a0 + (mint::mod() - a1) + (mint::mod() - a2na3iimag)) *
                        irot3.val();
                }
                if (s + 1 != (1 << (len - 2)))
                    irot *= info.irate3[countr_zero(~(unsigned int)(s))];
            }
            len -= 2;
        }
    }
}

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
std::vector<mint> convolution_naive(const std::vector<mint>& a,
                                    const std::vector<mint>& b) {
    int n = int(a.size()), m = int(b.size());
    std::vector<mint> ans(n + m - 1);
    if (n < m) {
        for (int j = 0; j < m; j++) {
            for (int i = 0; i < n; i++) {
                ans[i + j] += a[i] * b[j];
            }
        }
    } else {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                ans[i + j] += a[i] * b[j];
            }
        }
    }
    return ans;
}

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
std::vector<mint> convolution_fft(std::vector<mint> a, std::vector<mint> b) {
    int n = int(a.size()), m = int(b.size());
    int z = (int)internal::bit_ceil((unsigned int)(n + m - 1));
    a.resize(z);
    internal::butterfly(a);
    b.resize(z);
    internal::butterfly(b);
    for (int i = 0; i < z; i++) {
        a[i] *= b[i];
    }
    internal::butterfly_inv(a);
    a.resize(n + m - 1);
    mint iz = mint(z).inv();
    for (int i = 0; i < n + m - 1; i++) a[i] *= iz;
    return a;
}

}  // namespace internal

template <class mint, internal::is_static_modint_t<mint>* = nullptr>
std::vector<mint> convolution(std::vector<mint>&& a, std::vector<mint>&& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};

    int z = (int)internal::bit_ceil((unsigned int)(n + m - 1));
    assert((mint::mod() - 1) % z == 0);

    if (std::min(n, m) <= 60) return convolution_naive(a, b);
    return internal::convolution_fft(a, b);
}
template <class mint, internal::is_static_modint_t<mint>* = nullptr>
std::vector<mint> convolution(const std::vector<mint>& a,
                              const std::vector<mint>& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};

    int z = (int)internal::bit_ceil((unsigned int)(n + m - 1));
    assert((mint::mod() - 1) % z == 0);

    if (std::min(n, m) <= 60) return convolution_naive(a, b);
    return internal::convolution_fft(a, b);
}

template <unsigned int mod = 998244353,
          class T,
          std::enable_if_t<internal::is_integral<T>::value>* = nullptr>
std::vector<T> convolution(const std::vector<T>& a, const std::vector<T>& b) {
    int n = int(a.size()), m = int(b.size());
    if (!n || !m) return {};

    using mint = static_modint<mod>;

    int z = (int)internal::bit_ceil((unsigned int)(n + m - 1));
    assert((mint::mod() - 1) % z == 0);

    std::vector<mint> a2(n), b2(m);
    for (int i = 0; i < n; i++) {
        a2[i] = mint(a[i]);
    }
    for (int i = 0; i < m; i++) {
        b2[i] = mint(b[i]);
    }
    auto c2 = convolution(std::move(a2), std::move(b2));
    std::vector<T> c(n + m - 1);
    for (int i = 0; i < n + m - 1; i++) {
        c[i] = c2[i].val();
    }
    return c;
}

}  // namespace atcoder

using mint = atcoder::modint998244353;

int main() {
    SetFastIO();

    int N;
    std::cin >> N;
    std::vector<std::vector<int>> T(N);
    for (int i{} ; i < N - 1 ; i++) {
        int s, t;
        std::cin >> s >> t;
        s--; t--;
        T[s].push_back(t);
        T[t].push_back(s);
    }
    std::vector<bool> removed(N);
    std::vector<int> sz(N);
    auto calc_sz{[&](auto dfs, int v, int p) -> int {
        assert(!removed[v]);
        sz[v] = 1;
        for (auto x : T[v]) if (x != p and !removed[x]) {
            sz[v] += dfs(dfs, x, v);
        }
        return sz[v];
    }};
    auto cent{[&](int v) -> int {
        calc_sz(calc_sz, v, -1);
        int p{-1};
        bool fn{false};
        int all{sz[v]};
        while (!fn) {
            fn = true;
            for (auto x : T[v]) {
                if (x == p or removed[x] or 2 * sz[x] <= all) {
                    continue;
                }
                fn = false;
                p = v;
                v = x;
                break;
            }
        }
        return v;
    }};
    std::vector<mint> P(N + 1, mint{1});
    for (int i{1} ; i <= N ; i++) P[i] = P[i - 1] * mint::raw(i);
    std::vector<mint> I(N + 1);
    I[N] = P[N].inv();
    for (int i{N - 1} ; i >= 0 ; i--) I[i] = I[i + 1] * mint::raw(i + 1);
    auto comb{[&](int n, int r) -> mint {
        assert(0 <= n and n <= N);
        assert(0 <= r and r <= n);
        return P[n] * I[r] * I[n - r];
    }};
    std::vector<int> dep(N);
    auto calc_dep{[&](auto dfs, int v, int p, int d) -> void {
        assert(!removed[v]);
        dep[v] = d;
        for (auto x : T[v]) if (x != p and !removed[x]) {
            dfs(dfs, x, v, d + 1);
        }
    }};
    auto calc_max_dep{[&](auto dfs, int v, int p) -> int {
        assert(!removed[v]);
        int res{dep[v]};
        for (auto x : T[v]) if (x != p and !removed[x]) {
            res = std::max(res, dfs(dfs, x, v));
        }
        return res;
    }};
    auto calc_dep_cnt{[&](auto dfs, int v, int p, std::vector<mint>& dep_cnt) -> void {
        assert(!removed[v]);
        dep_cnt[dep[v]]++; 
        for (auto x : T[v]) if (x != p and !removed[x]) {
            dfs(dfs, x, v, dep_cnt);
        } 
    }};
    std::vector<mint> cnt(N + 1);
    const mint inv{mint::raw(2).inv()};
    auto dfs{[&](auto dfs, int v) -> void {
        v = cent(v);
        calc_dep(calc_dep, v, -1, 0);
        int sz{calc_max_dep(calc_max_dep, v, -1)};
        std::vector<mint> sum_sq(sz + 1);
        calc_dep_cnt(calc_dep_cnt, v, -1, sum_sq);
        sum_sq = atcoder::convolution(sum_sq, sum_sq);
        std::vector<mint> sq_sum(2 * sz + 1);
        for (auto x : T[v]) if (!removed[x]) {
            int max{calc_max_dep(calc_max_dep, x, v)};
            std::vector<mint> cur(max + 1);
            calc_dep_cnt(calc_dep_cnt, x, v, cur);
            cur = atcoder::convolution(cur, cur);
            for (int i{} ; i < (int)cur.size() ; i++) sq_sum[i] += cur[i];
        }
        assert(sq_sum.size() == sum_sq.size());
        for (int i{} ; i < std::min(N + 1, (int)sum_sq.size()) ; i++) {
            cnt[i] += inv * (sum_sq[i] - sq_sum[i]);
        }
        removed[v] = true;
        for (auto x : T[v]) if (!removed[x]) dfs(dfs, x);
    }};
    dfs(dfs, 0);
    std::vector<mint> L(N);
    for (int i{1} ; i < N + 1 ; i++) {
        L[i - 1] = cnt[i];
    }
    std::reverse(L.begin(), L.end());
    std::vector<mint> X(N), Y(N);
    for (int i{} ; i < N ; i++) {
        X[i] = P[N - 1 - i] * L[i];
        Y[i] = I[i];
    }
    std::vector<mint> ans{atcoder::convolution(X, Y)};
    for (int i{N - 1} ; i >= 1 ; i--) {
        ans[i] *= I[N - 1 - i];
        std::cout << ans[i].val() << '\n';
    }
}
accuracy: 1
time_ms: 510
memory_kb: 48844
final_rank: 2

code_snippet: #include <bits/stdc++.h>
#define fi first
#define se second
#define rep(i,s,n) for (int i = (s); i < (n); ++i)
#define rrep(i,n,g) for (int i = (n)-1; i >= (g); --i)
#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define len(x) (int)(x).size()
#define dup(x,y) (((x)+(y)-1)/(y))
#define pb push_back
#define eb emplace_back
#define Field(T) vector<vector<T>>
#define pq(T) priority_queue<T,vector<T>,greater<T>>
using namespace std;
using ll = long long;
using P = pair<int,int>;

template< int mod >
struct ModInt {
  int x;
  ModInt() : x(0) {}
  ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
  ModInt &operator+=(const ModInt &p) {
    if((x += p.x) >= mod) x -= mod;
    return *this;
  }
  ModInt &operator-=(const ModInt &p) {
    if((x += mod - p.x) >= mod) x -= mod;
    return *this;
  }
  ModInt &operator*=(const ModInt &p) {
    x = (int) (1LL * x * p.x % mod);
    return *this;
  }
  ModInt &operator/=(const ModInt &p) {
    *this *= p.inverse();
    return *this;
  }
  ModInt operator-() const { return ModInt(-x); }
  ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
  ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
  ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
  ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
  bool operator==(const ModInt &p) const { return x == p.x; }
  bool operator!=(const ModInt &p) const { return x != p.x; }

  ModInt inverse() const {
    int a = x, b = mod, u = 1, v = 0, t;
    while(b > 0) {
      t = a / b;
      swap(a -= t * b, b);
      swap(u -= t * v, v);
    }
  return ModInt(u);
  }

  ModInt pow(int64_t n) const {
    ModInt ret(1), mul(x);
    while(n > 0) {
      if(n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }

  friend ostream &operator<<(ostream &os, const ModInt &p) {
    return os << p.x;
  }

  friend istream &operator>>(istream &is, ModInt &a) {
    int64_t t;
    is >> t;
    a = ModInt< mod >(t);
    return (is);
  }

  static int get_mod() { return mod; }
};

using mint = ModInt<998244353>;
using vm = vector<mint>;
struct modinv {
  int n; vm d;
  modinv(): n(2), d({0,1}) {}
  mint operator()(int i) {
    while (n <= i) {
      d.pb(-d[mint::get_mod()%n]*(mint::get_mod()/n)), ++n;
    }
    return d[i];
  }
  mint operator[](int i) const { return d[i];}
} invs;
struct modfact {
  int n; vm d;
  modfact(): n(2), d({1,1}) {}
  mint operator()(int i) { while (n <= i) d.pb(d.back()*n), ++n; return d[i];}
  mint operator[](int i) const { return d[i];}
} facs;
struct modfactinv {
  int n; vm d;
  modfactinv(): n(2), d({1,1}) {}
  mint operator()(int i) { while (n <= i) d.pb(d.back()*invs(n)), ++n; return d[i];}
  mint operator[](int i) const { return d[i];}
} ifacs;
mint comb(int a, int b) {
  if (a < b || b < 0) return 0;
  return facs(a)*ifacs(b)*ifacs(a-b);
}

struct NumberTheoreticTransform {

  int mod = mint::get_mod();
  int mxb;
  mint r;

  NumberTheoreticTransform() {
    auto tmp = mod - 1;
    mxb = 0;
    while(tmp % 2 == 0) tmp >>= 1, mxb++;
    r = 2;
    while(r.pow((mod - 1) >> 1) == 1) r += 1;
    assert(r.pow(mod - 1) == 1);
    r = r.pow((mod - 1) >> mxb);
  }

  void ntt(vm &f, int lg, bool inv) {
    int sz = (int)f.size();
    for (int i = 0; i < sz; ++i) {
      int j = 0;
      for (int k = 0; k < lg; ++k) {
        j |= ((i >> k) & 1) << (lg - 1 - k);
      }
      if (i < j) swap(f[i], f[j]);
    }

    for (int i = 0; i < lg; ++i) {
      int b = 1 << i;
      mint now = 1;
      mint z = r.pow(1 << (mxb - 1 - i));
      if (inv) z = z.inverse();
      for (int j = 0; j < b; ++j) {
        for (int k = 0; k < sz; k += b*2) {
          mint s = f[j + k];
          mint t = f[j + k + b] * now;
          f[j + k] = s + t;
          f[j + k + b] = s - t;
        }
        now *= z;
      }
    }
  }

  vm multiply(const vm &f, const vm &g) {
    vm nf, ng;
    size_t need = f.size() + g.size() - 1;
    int sz = 1, lg = 0;
    while(sz < (int)(f.size() + g.size())) {
      sz *= 2;
      ++lg;
    }
    nf.resize(sz), ng.resize(sz);
    for (int i = 0; i < (int)f.size(); ++i) {
      nf[i] = f[i];
    }
    for (int i = 0; i < (int)g.size(); ++i) {
      ng[i] = g[i];
    }
    ntt(nf, lg, 0);
    ntt(ng, lg, 0);
    for (int i = 0; i < sz; ++i) {
      nf[i] *= ng[i];
    }
    ntt(nf, lg, 1);
    vm ret(sz);
    mint inv_sz = mint(1)/sz;
    for (int i = 0; i < sz; ++i) {
      ret[i] = nf[i] * inv_sz;
    }
    ret.resize(need);
    return ret;
  }
} ntt;

struct FPS : vm {
#define d (*this)
#define s int(vm::size())
  template<class...Args> FPS(Args...args): vm(args...) {}
  FPS(initializer_list<mint> a): vm(all(a)) {}
  int size() const { return vm::size();}
  void rsz(int n) { if (s < n) resize(n);}
  FPS& low_(int n) { resize(n); return d;}
  FPS low(int n) const { return FPS(d).low_(n);}
  FPS low(FPS a, int n) const { return a.low_(n);}
  FPS& rev_() { reverse(all(d)); return d;}
  FPS rev() const { return FPS(d).rev_();}
  FPS rev(FPS a) const { return a.rev_();}
  mint& operator[](int i) { rsz(i+1); return vm::operator[](i);}
  mint operator[](int i) const { return i<s ? vm::operator[](i) : 0;}
  mint operator()(mint x) const { mint r; rrep(i,s,0) r = r*x+d[i]; return r;}
  FPS operator<<(int a) const { FPS r(d); r.insert(r.begin(), a, 0); return r;}
  FPS operator>>(int a) const { FPS r(d); r.rsz(a); r.erase(r.begin(), r.begin()+a); return r;}
  FPS& fit() { while (s && !back().x) pop_back(); return d;}
  FPS operator-() const { FPS r(d); rep(i,0,s) r[i] = -r[i]; return r;}
  FPS& operator+=(const FPS& a) { rsz(len(a)); rep(i,0,len(a)) d[i] += a[i]; return d;}
  FPS& operator-=(const FPS& a) { rsz(len(a)); rep(i,0,len(a)) d[i] -= a[i]; return d;}
  FPS& operator*=(const FPS& a) { return d = ntt.multiply(a, d);}
  FPS& operator/=(const FPS& a) {
    int w = s-len(a)+1; if (w <= 0) return d = 0;
    return (rev_().low_(w) *= a.rev().inv(w)).low_(w).rev_();
  }
  FPS& operator%=(const FPS& a) { return (d -= d/a*a).low_(len(a)-1);}
  FPS& operator*=(mint a) { rep(i,0,s) d[i] *= a; return d;}
  FPS& operator/=(mint a) { return d *= a.inverse();}
  FPS& operator*=(int a) { return d *= mint(a);}
  FPS& operator/=(int a) { return d /= mint(a);}
  FPS operator+(const FPS& a) const { return FPS(d) += a;}
  FPS operator-(const FPS& a) const { return FPS(d) -= a;}
  FPS operator*(const FPS& a) const { return FPS(d) *= a;}
  FPS operator/(const FPS& a) const { return FPS(d) /= a;}
  FPS operator%(const FPS& a) const { return FPS(d) %= a;}
  FPS operator*(mint a) const { return FPS(d) *= a;}
  FPS operator/(mint a) const { return FPS(d) *= a.inverse();}
  FPS operator*(int a) const { return FPS(d) *= mint(a);}
  FPS operator/(int a) const { return FPS(d) /= mint(a);}
  FPS& mul1(mint a) { pb(0); rrep(i,s-1,0) d[i+1] += d[i], d[i] *= a; return d;} // *=(x+a), /=(x+a)
  FPS& div1(mint a) { mint pre = back(); pop_back(); rrep(i,s,0) std::swap(pre, d[i]), pre -= d[i]*a; return d;}
  FPS dif() const { FPS r(s-1); rep(i,1,len(r)) r[i-1] = d[i]*i; return r;}
  FPS integ() const { FPS r(s+1); rep(i,1,s) r[i] = d[i-1]*invs(i); return r;}
  FPS inv() const { return inv(s);}
  FPS inv(int w) const {
    FPS r({d[0].inverse()});
    for (int i = 1; i < w; i <<= 1) r = r*2 - low(r*r*low(i<<1), i<<1);
    return r.low_(w);
  }
  vm operator()(const vm& x) const {
    int n = len(x), n2 = n<<1;
    vector<FPS> t(n2);
    rep(i,0,n) t[n+i] = {-x[i],1};
    for (int i = n-1; i; --i) t[i] = t[i<<1]*t[i<<1|1];
    t[1] = d%t[1];
    rep(i,2,n2) t[i] = t[i>>1]%t[i];
    vm r(n);
    rep(i,0,n) r[i] = t[n+i][0];
    return r;
  }
  FPS shift(mint c) const {
    FPS res;
    vm a(s), b(s,1);
    rep(i,0,s) a[i] = d[i]*facs(i);
    rrep(i,s-1,0) b[i] = b[i+1]*c;
    rep(i,0,s) b[i] *= ifacs(s-1-i);
    a = ntt.multiply(a,b);
    rep(i,0,s) res[i] = a[s-1+i]*ifacs[i];
    return res;
  }
#undef s
#undef d
};

struct Centroid {
  vector<vector<int>> G, Cg;
  vector<int> sz, dead;

  Centroid(int n) : G(n), Cg(n), sz(n, 1), dead(n, 0) {}

  void add_edge(int u, int v) {
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  int dfs(int v, int p) {
    sz[v] = 1;
    for (int nv : G[v]) {
      if (nv == p || dead[nv]) continue;
      sz[v] += dfs(nv, v);
    }
    return sz[v];
  }

  int find(int v, int p, int tmp) {
    for (int nv : G[v]) {
      if (nv == p || dead[nv]) continue;
      if (sz[nv] > tmp/2) return find(nv, v, tmp);
    }
    return v;
  }

  int build(int x = 0) {
    int c = find(x, -1, dfs(x, -1));
    dead[c] = true;
    for (auto nv : G[c]) {
      if (!dead[nv]) {
        Cg[c].emplace_back(build(nv));
      }
    }
    dead[c] = false;
    return c;
  }
};

int main() {
  int n;
  cin >> n;
  Centroid cent(n);
  rep(i,0,n-1) {
    int s, t;
    cin >> s >> t;
    --s, --t;
    cent.add_edge(s, t);
  }
  int r = cent.build();
  FPS dep, a(len(cent.G)-1);
  int d = 0;
  function<void(int,int)> dfs = [&](int v, int p) {
    if (len(dep) == d) {
      dep.push_back(1);
    } else {
      dep[d] += 1;
    }
    ++d;
    for (auto nv : cent.G[v]) {
      if (nv == p || cent.dead[nv]) continue;
      dfs(nv, v);
    }
    --d;
  };
  function<void(int)> cdfs = [&](int c) {
    cent.dead[c] = true;
    FPS s = {0};
    for (auto nv : cent.G[c]) {
      if (cent.dead[nv]) continue;
      dep.clear();
      dfs(nv, -1);
      a += (s * dep) << 1;
      s += dep;
      a += dep;
    }
    for (auto nc : cent.Cg[c]) {
      cdfs(nc);
    }
  };
  cdfs(r);
  a = a.shift(1);
  rep(i,0,n-1) {
    cout << a[i] << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 1070
memory_kb: 52800
final_rank: 7

code_snippet: #include <bits/stdc++.h>

using ll = long long;

template <class T> using Vec = std::vector<T>;

template <class F> struct RecLambda : private F {
    explicit RecLambda(F&& f): F(std::forward<F>(f)) {}
    template <class... Args> decltype(auto) operator()(Args&&... args) const {
        return F::operator()(*this, std::forward<Args>(args)...);
    }
};

constexpr int MOD = 998244353;
constexpr int PROOT = 3;

struct Fp {
    int x;
    Fp() : x(0) {}
    Fp(int v): x(v) {}
    Fp& operator += (const Fp& t) {
        if ((x += t.x) >= MOD) x -= MOD;
        return *this;
    }
    Fp operator + (const Fp& t) const {
        return Fp(*this) += t;
    }
    Fp& operator -= (const Fp& t) {
        if ((x += MOD - t.x) >= MOD) x -= MOD;
        return *this;
    }
    Fp operator - (const Fp& t) const {
        return Fp(*this) -= t;
    }
    Fp& operator *= (const Fp& t) {
        return *this = *this * t;
    }
    Fp operator * (const Fp& t) const {
        return Fp((ll) x * t.x % MOD);
    }
    Fp pow(int e) const {
        Fp ret(1), mul(*this);
        while (e > 0) {
            if (e & 1) ret *= mul;
            mul *= mul;
            e >>= 1;
        }
        return ret;
    }
    Fp inv() const {
        return pow(MOD - 2);
    }
    Fp& operator /= (const Fp& t) {
        return *this *= t.inv();
    }
    Fp operator / (const Fp& t) const {
        return *this * t.inv();
    }
};

void butterfly(Vec<Fp>& a, bool inv = false) {
    int n = a.size();
    int d = __builtin_ctz(n);
    for (int i = 0; i < n; ++i) {
        int j = 0;
        for (int k = 0; k < d; ++k) {
            if (i >> k & 1) {
                j |= 1 << (d - k - 1);
            }
        }
        if (i < j) {
            std::swap(a[i], a[j]);
        }
    }
    Vec<Fp> coeff(d);
    coeff[d - 1] = (inv ? Fp(PROOT).inv() : Fp(PROOT)).pow((MOD - 1) >> d); 
    for (int i = d - 1; i > 0; --i) {
        coeff[i - 1] = coeff[i] * coeff[i];
    }
    for (int s = 0; s < d; ++s) {
        int mh = 1 << s;
        int m = mh << 1;
        for (int i = 0; i < n; i += m) {
            Fp c = 1;
            for (int j = i; j < i + mh; ++j) {
                Fp x = a[j], y = a[j + mh] * c;
                a[j] = x + y;
                a[j + mh] = x - y;
                c *= coeff[s];
            }
        }
    }
}

Vec<Fp> convolution(Vec<Fp> a, Vec<Fp> b) {
    if (a.empty() or b.empty()) return {};
    int len = a.size() + b.size() - 1;
    if (len == 1) return {a[0] * b[0]};
    int sz = 1;
    while (sz < len) {
        sz *= 2;
    }
    a.resize(sz);
    b.resize(sz);
    butterfly(a);
    butterfly(b);
    for (int i = 0; i < sz; ++i) {
        a[i] *= b[i];
    }
    butterfly(a, true);
    a.resize(len);
    auto inv = Fp(sz).inv();
    for (auto& x : a) {
        x *= inv;
    }
    return a;
}

Vec<Fp> square(Vec<Fp> a) {
    if (a.empty()) return {};
    int len = 2 * a.size() - 1;
    if (len == 1) return {a[0] * a[0]};
    int sz = 1;
    while (sz < len) {
        sz *= 2;
    }
    a.resize(sz);
    butterfly(a);
    for (auto& x : a) {
        x *= x;
    }
    butterfly(a, true);
    a.resize(len);
    auto inv = Fp(sz).inv();
    for (auto& x : a) {
        x *= inv;
    }
    return a;
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;
    Vec<Vec<int>> graph(n);
    for (int i = 1; i < n; ++i) {
        int s, t;
        std::cin >> s >> t;
        s -= 1, t -= 1;
        graph[s].push_back(t);
        graph[t].push_back(s);
    }

    Vec<char> used(n);
    Vec<int> subtree(n);
    
    
    const auto setup = RecLambda([&](auto&& dfs, int u, int p) -> void {
        subtree[u] = 1;
        for (int v : graph[u]) {
            if (v != p and !used[v]) {
                dfs(v, u);
                subtree[u] += subtree[v];
            }
        } 
    });

    const auto search = RecLambda([&](auto&& dfs, int u, int p, int d, Vec<Fp>& count) -> void {
        if (d >= (int)count.size()) {
            count.emplace_back();
        }
        count[d] += 1;
        for (int v : graph[u]) {
            if (v != p and !used[v]) {
                dfs(v, u, d + 1, count);
            }
        }
    });

    Vec<Fp> exact(n - 1);

    const auto decompose = RecLambda([&](auto&& dfs, int u, int p, int whole) -> void {
        for (int v : graph[u]) {
            if (v != p and !used[v] and subtree[v] * 2 > whole) {
                dfs(v, u, whole);
                return;
            }
        }
        used[u] = true;
        Vec<Fp> sum;
        for (int v : graph[u]) {
            if (used[v]) continue;
            Vec<Fp> count;
            search(v, u, 0, count);
            for (int i = 0; i < (int)count.size(); ++i) {
                if (i >= (int)sum.size()) {
                    sum.emplace_back();
                }
                sum[i] += count[i];
                exact[i] += Fp(2) * count[i];
            }
            count = square(count);
            for (int i = 0; i < std::min(n - 2, (int)count.size()); ++i) {
                exact[i + 1] -= count[i];
            }
        }
        sum = square(sum);
        for (int i = 0; i < std::min(n - 2, (int)sum.size()); ++i) {
            exact[i + 1] += sum[i];
        }
        for (int v : graph[u]) {
            if (used[v]) continue;
            setup(v, u);
            dfs(v, u, subtree[v]);
        }
    });

    setup(0, -1);
    decompose(0, -1, n);

    Vec<Fp> fact(n), ifact(n);
    fact[0] = 1;
    for (int i = 1; i < n; ++i) {
        fact[i] = fact[i - 1] * Fp(i);
    }
    ifact.back() = fact.back().inv();
    for (int i = n - 1; i > 0; --i) {
        ifact[i - 1] = ifact[i] * Fp(i);
    }

    Vec<Fp> coeff(n - 1);
    for (int i = 0; i < n - 1; ++i) {
        exact[i] *= Fp((998244353 + 1) / 2);
        exact[i] *= fact[i];
        coeff[i] = ifact[n - i - 2];
    }

    Vec<Fp> ans = convolution(exact, coeff);
    for (int i = 0; i < n - 1; ++i) {
        std::cout << (ans[i + n - 2] * ifact[i]).x << '\n';
    }

    return 0;
}
accuracy: 1
time_ms: 1380
memory_kb: 73904
final_rank: 12

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i = 0; i < (n); i++)
using namespace std;
typedef long long ll;

template<int MOD> struct Fp {
    long long val;
    constexpr Fp(long long v = 0) noexcept : val(v % MOD) {
        if (val < 0) val += MOD;
    }
    constexpr int getmod() const { return MOD; }
    constexpr Fp operator - () const noexcept {
        return val ? MOD - val : 0;
    }
    constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r; }
    constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r; }
    constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r; }
    constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r; }
    constexpr Fp& operator += (const Fp& r) noexcept {
        val += r.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }
    constexpr Fp& operator -= (const Fp& r) noexcept {
        val -= r.val;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr Fp& operator *= (const Fp& r) noexcept {
        val = val * r.val % MOD;
        return *this;
    }
    constexpr Fp& operator /= (const Fp& r) noexcept {
        long long a = r.val, b = MOD, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b, swap(a, b);
            u -= t * v, swap(u, v);
        }
        val = val * u % MOD;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr bool operator == (const Fp& r) const noexcept {
        return this->val == r.val;
    }
    constexpr bool operator != (const Fp& r) const noexcept {
        return this->val != r.val;
    }
    constexpr bool operator < (const Fp& r) const noexcept {
        return this->val < r.val;
    }
    friend constexpr istream& operator >> (istream& is, Fp<MOD>& x) noexcept {
        is >> x.val;
        x.val %= MOD;
        if (x.val < 0) x.val += MOD;
        return is;
    }
    friend constexpr ostream& operator << (ostream& os, const Fp<MOD>& x) noexcept {
        return os << x.val;
    }
    friend constexpr Fp<MOD> modpow(const Fp<MOD>& a, long long n) noexcept {
        if (n == 0) return 1;
        auto t = modpow(a, n / 2);
        t = t * t;
        if (n & 1) t = t * a;
        return t;
    }
};

// NTT
namespace NTT {
    long long modpow(long long a, long long n, int mod) {
        long long res = 1;
        while (n > 0) {
            if (n & 1) res = res * a % mod;
            a = a * a % mod;
            n >>= 1;
        }
        return res;
    }

    long long modinv(long long a, int mod) {
        long long b = mod, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b, swap(a, b);
            u -= t * v, swap(u, v);
        }
        u %= mod;
        if (u < 0) u += mod;
        return u;
    }

    int calc_primitive_root(int mod) {
        if (mod == 2) return 1;
        if (mod == 167772161) return 3;
        if (mod == 469762049) return 3;
        if (mod == 754974721) return 11;
        if (mod == 998244353) return 3;
        int divs[20] = {};
        divs[0] = 2;
        int cnt = 1;
        long long x = (mod - 1) / 2;
        while (x % 2 == 0) x /= 2;
        for (long long i = 3; i * i <= x; i += 2) {
            if (x % i == 0) {
                divs[cnt++] = i;
                while (x % i == 0) x /= i;
            }
        }
        if (x > 1) divs[cnt++] = x;
        for (int g = 2;; g++) {
            bool ok = true;
            for (int i = 0; i < cnt; i++) {
                if (modpow(g, (mod - 1) / divs[i], mod) == 1) {
                    ok = false;
                    break;
                }
            }
            if (ok) return g;
        }
    }

    int get_fft_size(int N, int M) {
        int size_a = 1, size_b = 1;
        while (size_a < N) size_a <<= 1;
        while (size_b < M) size_b <<= 1;
        return max(size_a, size_b) << 1;
    }

    // number-theoretic transform
    template<class mint> void trans(vector<mint> &v, bool inv = false) {
        if (v.empty()) return;
        int N = (int)v.size();
        int MOD = v[0].getmod();
        int PR = calc_primitive_root(MOD);
        static bool first = true;
        static vector<long long> vbw(30), vibw(30);
        if (first) {
            first = false;
            for (int k = 0; k < 30; ++k) {
                vbw[k] = modpow(PR, (MOD - 1) >> (k + 1), MOD);
                vibw[k] = modinv(vbw[k], MOD);
            }
        }
        for (int i = 0, j = 1; j < N - 1; j++) {
            for (int k = N >> 1; k > (i ^= k); k >>= 1);
            if (i > j) swap(v[i], v[j]);
        }
        for (int k = 0, t = 2; t <= N; ++k, t <<= 1) {
            long long bw = vbw[k];
            if (inv) bw = vibw[k];
            for (int i = 0; i < N; i += t) {
                mint w = 1;
                for (int j = 0; j < t/2; ++j) {
                    int j1 = i + j, j2 = i + j + t/2;
                    mint c1 = v[j1], c2 = v[j2] * w;
                    v[j1] = c1 + c2;
                    v[j2] = c1 - c2;
                    w *= bw;
                }
            }
        }
        if (inv) {
            long long invN = modinv(N, MOD);
            for (int i = 0; i < N; ++i) v[i] = v[i] * invN;
        }
    }

    // for garner
    static constexpr int MOD0 = 754974721;
    static constexpr int MOD1 = 167772161;
    static constexpr int MOD2 = 469762049;
    using mint0 = Fp<MOD0>;
    using mint1 = Fp<MOD1>;
    using mint2 = Fp<MOD2>;
    static const mint1 imod0 = 95869806; // modinv(MOD0, MOD1);
    static const mint2 imod1 = 104391568; // modinv(MOD1, MOD2);
    static const mint2 imod01 = 187290749; // imod1 / MOD0;

    // small case (T = mint, long long)
    template<class T> vector<T> naive_mul 
    (const vector<T> &A, const vector<T> &B) {
        if (A.empty() || B.empty()) return {};
        int N = (int)A.size(), M = (int)B.size();
        vector<T> res(N + M - 1);
        for (int i = 0; i < N; ++i)
            for (int j = 0; j < M; ++j)
                res[i + j] += A[i] * B[j];
        return res;
    }

    // mint
    template<class mint> vector<mint> mul
    (const vector<mint> &A, const vector<mint> &B) {
        if (A.empty() || B.empty()) return {};
        int N = (int)A.size(), M = (int)B.size();
        if (min(N, M) < 30) return naive_mul(A, B);
        int MOD = A[0].getmod();
        int size_fft = get_fft_size(N, M);
        if (MOD == 998244353) {
            vector<mint> a(size_fft), b(size_fft), c(size_fft);
            for (int i = 0; i < N; ++i) a[i] = A[i];
            for (int i = 0; i < M; ++i) b[i] = B[i];
            trans(a), trans(b);
            vector<mint> res(size_fft);
            for (int i = 0; i < size_fft; ++i) res[i] = a[i] * b[i];
            trans(res, true);
            res.resize(N + M - 1);
            return res;
        }
        vector<mint0> a0(size_fft, 0), b0(size_fft, 0), c0(size_fft, 0);
        vector<mint1> a1(size_fft, 0), b1(size_fft, 0), c1(size_fft, 0);
        vector<mint2> a2(size_fft, 0), b2(size_fft, 0), c2(size_fft, 0);
        for (int i = 0; i < N; ++i)
            a0[i] = A[i].val, a1[i] = A[i].val, a2[i] = A[i].val;
        for (int i = 0; i < M; ++i)
            b0[i] = B[i].val, b1[i] = B[i].val, b2[i] = B[i].val;
        trans(a0), trans(a1), trans(a2), trans(b0), trans(b1), trans(b2);
        for (int i = 0; i < size_fft; ++i) {
            c0[i] = a0[i] * b0[i];
            c1[i] = a1[i] * b1[i];
            c2[i] = a2[i] * b2[i];
        }
        trans(c0, true), trans(c1, true), trans(c2, true);
        static const mint mod0 = MOD0, mod01 = mod0 * MOD1;
        vector<mint> res(N + M - 1);
        for (int i = 0; i < N + M - 1; ++i) {
            int y0 = c0[i].val;
            int y1 = (imod0 * (c1[i] - y0)).val;
            int y2 = (imod01 * (c2[i] - y0) - imod1 * y1).val;
            res[i] = mod01 * y2 + mod0 * y1 + y0;
        }
        return res;
    }

    // long long
    vector<long long> mul_ll
    (const vector<long long> &A, const vector<long long> &B) {
        if (A.empty() || B.empty()) return {};
        int N = (int)A.size(), M = (int)B.size();
        if (min(N, M) < 30) return naive_mul(A, B);
        int size_fft = get_fft_size(N, M);
        vector<mint0> a0(size_fft, 0), b0(size_fft, 0), c0(size_fft, 0);
        vector<mint1> a1(size_fft, 0), b1(size_fft, 0), c1(size_fft, 0);
        vector<mint2> a2(size_fft, 0), b2(size_fft, 0), c2(size_fft, 0);
        for (int i = 0; i < N; ++i)
            a0[i] = A[i], a1[i] = A[i], a2[i] = A[i];
        for (int i = 0; i < M; ++i)
            b0[i] = B[i], b1[i] = B[i], b2[i] = B[i];
        trans(a0), trans(a1), trans(a2), trans(b0), trans(b1), trans(b2);
        for (int i = 0; i < size_fft; ++i) {
            c0[i] = a0[i] * b0[i];
            c1[i] = a1[i] * b1[i];
            c2[i] = a2[i] * b2[i];
        }
        trans(c0, true), trans(c1, true), trans(c2, true);
        static const long long mod0 = MOD0, mod01 = mod0 * MOD1;
        vector<long long> res(N + M - 1);
        for (int i = 0; i < N + M - 1; ++i) {
            int y0 = c0[i].val;
            int y1 = (imod0 * (c1[i] - y0)).val;
            int y2 = (imod01 * (c2[i] - y0) - imod1 * y1).val;
            res[i] = mod01 * y2 + mod0 * y1 + y0;
        }
        return res;
    }
};

// Binomial coefficient
template<class T> struct BiCoef {
    vector<T> fact_, inv_, finv_;
    constexpr BiCoef() {}
    constexpr BiCoef(int n) noexcept : fact_(n, 1), inv_(n, 1), finv_(n, 1) {
        init(n);
    }
    constexpr void init(int n) noexcept {
        fact_.assign(n, 1), inv_.assign(n, 1), finv_.assign(n, 1);
        int MOD = fact_[0].getmod();
        for(int i = 2; i < n; i++){
            fact_[i] = fact_[i-1] * i;
            inv_[i] = -inv_[MOD%i] * (MOD/i);
            finv_[i] = finv_[i-1] * inv_[i];
        }
    }
    constexpr T com(int n, int k) const noexcept {
        if (n < k || n < 0 || k < 0) return 0;
        return fact_[n] * finv_[k] * finv_[n-k];
    }
    constexpr T fact(int n) const noexcept {
        if (n < 0) return 0;
        return fact_[n];
    }
    constexpr T inv(int n) const noexcept {
        if (n < 0) return 0;
        return inv_[n];
    }
    constexpr T finv(int n) const noexcept {
        if (n < 0) return 0;
        return finv_[n];
    }
};

const int MOD = 998244353;
using mint = Fp<MOD>;

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

    int N; cin >> N;
    vector<vector<int>> G(N);
    rep(i,N-1){
        int u,v; cin >> u >> v; u--; v--;
        G[u].push_back(v);
        G[v].push_back(u);
    }

    vector<int> sz(N), dead(N, 0);
    auto centroid = [&](int root) {
        function<void(int,int)> get_size = [&](int v, int p) -> void {
            sz[v] = 1;
            for(int to : G[v]) {
                if(to == p || dead[to]) continue;
                get_size(to, v);
                sz[v] += sz[to];
            }
        }; get_size(root, -1);

        int M = sz[root];
        function<int(int,int)> dfs = [&](int v, int p) -> int {
            for(int to : G[v]) {
                if(to == p || dead[to]) continue;
                if(sz[to] > M / 2) return dfs(to, v);
            }
            return v;
        };  return dfs(root, -1);
    };

    vector<mint> ans(N, 0);
    function<void(int)> rec = [&](int v) {
        int c = centroid(v);
        dead[c] = true;
        for(int to : G[c]) {
            if(dead[to]) continue;
            rec(to);
        }

        vector<mint> whole_depth;
        whole_depth.push_back(1);

        for(int to : G[c]) {
            if(dead[to]) continue;
            vector<mint> depth;
            function<void(int,int,int)> calc_depth = [&](int v, int p, int d) -> void {
                while(whole_depth.size() <= d) whole_depth.push_back(0);
                while(depth.size() <= d) depth.push_back(0);
                whole_depth[d] += 1;
                depth[d] += 1;
                for(int u : G[v]) {
                    if(u == p || dead[u]) continue;
                    calc_depth(u, v, d + 1);
                }
            }; calc_depth(to, c, 1);

            auto res = NTT::mul(depth, depth);
            for(int i = 0; i < min(ans.size(), res.size()); i++) ans[i] -= res[i];
        }

        auto whole_res = NTT::mul(whole_depth, whole_depth);
        for(int i = 0; i < min(ans.size(), whole_res.size()); i++) ans[i] += whole_res[i];
        dead[c] = false;
    }; rec(0);

    ans.erase(ans.begin()); ans.push_back(0);
    BiCoef<mint> bc(220000);
    rep(i,ans.size()) ans[i] *= bc.fact(i) * bc.inv(2);
    reverse(ans.begin(), ans.end());
    vector<mint> coef(N + 1);
    rep(i,N+1) coef[i] = bc.finv(i);
    ans = NTT::mul(ans, coef);
    ans.resize(N);
    reverse(ans.begin(), ans.end());
    rep(i,N) ans[i] *= bc.finv(i);
    rep(i,N-1) cout << ans[i] << '\n';
}
accuracy: 1
time_ms: 900
memory_kb: 58996
final_rank: 8

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;
#define rep(i,n) for(int i=0; i<(n); i++)


#include <vector>
#include <algorithm>


template<unsigned int MOD>
u64 powm(u64 a, u64 i) {
    if (i == 0) return 1;
    u64 r = powm<MOD>(a * a % MOD, i / 2);
    if (i & 1) r = r * a % MOD;
    return r;
}


template<unsigned int MOD>
void NTT(vector<u64>& A, u64 g) {
    int N = 1;
    while (N < A.size()) N *= 2;
    for (int i = 0, j = 0; j < N; j++) {
        if (i < j) swap(A[i], A[j]);
        for (int k = N >> 1; k > (i ^= k); k >>= 1);
    }
    for (int i = 1; i < N; i <<= 1) {
        u64 q = powm<MOD>(g, (MOD - 1) / i / 2), qj = 1;
        for (int j = 0; j < i; j++) {
            for (int k = j; k < N; k += i * 2) {
                u64 l = A[k];
                u64 r = A[k + i] * qj % MOD;
                A[k] = l + r;
                if (A[k] >= MOD) A[k] -= MOD;
                A[k + i] = l + MOD - r;
                if (A[k + i] >= MOD) A[k + i] -= MOD;
            }
            qj = qj * q % MOD;
        }
    }
}


template<unsigned int MOD, unsigned int g>
vector<u64> convolution_static(const vector<u64>& A, const vector<u64>& B) {
    int reqsize = A.size() + B.size() - 1;
    int Z = 1; while (Z < reqsize) Z *= 2;
    vector<u64> Ax(Z), Bx(Z);
    vector<u64> res(reqsize);
    u64 iZ = powm<MOD>(Z, MOD - 2);
    rep(i, A.size()) Ax[i] = A[i];
    rep(i, B.size()) Bx[i] = B[i];
    NTT<MOD>(Ax, g); NTT<MOD>(Bx, g);
    rep(i, Z) Ax[i] = Ax[i] * Bx[i] % MOD;
    NTT<MOD>(Ax, g);
    reverse(Ax.begin() + 1, Ax.end());
    rep(i, Z) Ax[i] = Ax[i] * iZ % MOD;
    Ax.resize(A.size() + B.size() - 1);
    return move(Ax);
}

/*
vector<u64> convolution(const vector<u64>& A, const vector<u64>& B) {
    static const u64 MOD0 = 998244353;
    static const u64 MOD1 = 1107296257;
    vector<u64> res0 = convolution_static<MOD0, 3>(A, B);
    vector<u64> res1 = convolution_static<MOD1, 10>(A, B);
    vector<u64> res(res0.size());
    u64 t = powm<MOD1>(MOD0, MOD1 - 2);
    rep(i, res.size()) {
        u64 x = res1[i] + MOD1 - res0[i];
        if (x >= MOD1) x -= MOD1;
        x = x * t % MOD1;
        res[i] = res0[i] + x * MOD0;
    }
    return res;
}
*/
vector<u64> convolution(const vector<u64>& A, const vector<u64>& B) {
    return convolution_static<998244353,3>(A,B);
}


vector<u64> frequency_table_of_tree_distance(const vector<vector<int>>& E) {
    int n = E.size();
    vector<int> Z(n, 1);
    vector<u64> ans(n, 0);
    auto dfsz = [&](int p, int pre, auto dfsz)->void {
        for (int e : E[p]) if (e != pre) {
            dfsz(e, p, dfsz);
            Z[p] += Z[e];
        }
    };
    dfsz(0, -1, dfsz);
    auto dfsmain = [&](int s, auto dfsmain)->void {
        if (Z[s] == 1) { Z[s] = 0; return; }
        while (true) {
            int mxz = E[s][0];
            for (int e : E[s]) if (Z[e] > Z[mxz]) mxz = e;
            if (Z[mxz] * 2 > Z[s]) { Z[s] -= Z[mxz]; Z[mxz] += Z[s]; s = mxz; }
            else break;
        }
        Z[s] = 0;
        vector<vector<u64>> dcnt;
        for (int s2 : E[s]) if (Z[s2] != 0) {
            vector<int> I = { s2 };
            vector<int> D = { 1 };
            vector<int> P = { -1 };
            rep(i, I.size()) {
                int p = I[i];
                for (int e : E[p]) if (e != P[i]) if (Z[e] != 0) {
                    I.push_back(e);
                    D.push_back(D[i] + 1);
                    P.push_back(p);
                }
            }
            vector<u64> tmp(D.back() + 1);
            for (int d : D) tmp[d]++;
            dcnt.emplace_back(move(tmp));
        }

        sort(dcnt.begin(), dcnt.end(),
            [](const vector<u64>& l, const vector<u64>& r)->bool
            { return l.size() < r.size(); }
        );
        rep(i, dcnt.size() - 1) {
            vector<u64> tmp = convolution(dcnt[i + 1], dcnt[i]);
            rep(k, tmp.size()) ans[k] += tmp[k];
            rep(k, dcnt[i].size()) dcnt[i + 1][k] += dcnt[i][k];
        }
        rep(k, dcnt.back().size()) ans[k] += dcnt.back()[k];

        for (int s2 : E[s]) if (Z[s2] != 0) dfsmain(s2, dfsmain);
    };
    dfsmain(0, dfsmain);
    return ans;
}

const u64 MOD = 998244353;


int main(){
  int N; cin >> N;
  vector<vector<int>> E(N);
  rep(i,N-1){
    int u,v; cin >> u >> v; u--; v--;
    E[u].push_back(v);
    E[v].push_back(u);
  }

  vector<u64> F(N+1,1);
  for(int i=1; i<=N; i++) F[i] = F[i-1] * i % MOD;
  vector<u64> I(N+1,1);
  for(int i=2; i<=N; i++) I[i] = (MOD - MOD / i) * I[MOD%i] % MOD;
  vector<u64> iF(N+1,1);
  for(int i=1; i<=N; i++) iF[i] = iF[i-1] * I[i] % MOD;

  auto res = frequency_table_of_tree_distance(E);
  for(int i=1; i<res.size(); i++) res[i-1] = res[i];
  res.back() = 0;
  rep(i,res.size()) res[i] = res[i] * F[i] % MOD;
  reverse(res.begin(), res.end());
  res = convolution(res, iF);
  res.resize(N);
  reverse(res.begin(), res.end());
  rep(i,res.size()) res[i] = res[i] * iF[i] % MOD;
  rep(i,N-1) cout << res[i] << "\n";
  return 0;
}




struct ios_do_not_sync {
    ios_do_not_sync() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    }
} ios_do_not_sync_instance;
accuracy: 1
time_ms: 520
memory_kb: 52032
final_rank: 5

code_snippet: #include <bits/stdc++.h>

using namespace std;

struct FastIO {
    const static int ibufsiz = 4<<20, obufsiz = 18<<20;
    char ibuf[ibufsiz], *ipos = ibuf, obuf[obufsiz], *opos = obuf;
    FastIO() { fread(ibuf, 1, ibufsiz, stdin); }
    ~FastIO() { fwrite(obuf, 1, opos - obuf, stdout); }
    template<class T> FastIO& operator>>(T &x) {
        bool sign = 0; while (!isdigit(*ipos)) { if (*ipos == '-') sign = 1; ++ipos; } 
        x = *ipos++ & 15;
        while (isdigit(*ipos)) x = x * 10 + (*ipos++ & 15);
        if (sign) x = -x;
        return *this;
    }
    template<class T> FastIO& operator<<(T n) {
        static char _buf[18];
        char* _pos = _buf;
        if (n < 0) *opos++ = '-', n = -n;
        do *_pos++ = '0' + n % 10; while (n /= 10);
        while (_pos != _buf) *opos++ = *--_pos;
        return *this;
    }
    FastIO& operator<<(char ch) { *opos++ = ch; return *this; }
};

const long long mod = 998244353, G = 3, Gi = (mod + 1) / 3;

template <unsigned mod> struct modint {
    unsigned val;
public:
    modint() : val(0) {}
    template <class T> modint(T x) { x %= mod; if (x < 0) x += mod; val = (unsigned)x; }
    modint& operator++() { val++; if (val == mod) val = 0; return *this; }
    modint& operator--() { if (val == 0) val = mod; val--; return *this; }
    modint& operator+=(const modint &x) { val += x.val; if (val >= mod) val -= mod; return *this; }
    modint& operator-=(const modint &x) { val -= x.val; if (val >= mod) val += mod; return *this; }
    modint& operator*=(const modint &x) { val = 1ull * val * x.val % mod; return *this; }
    modint& operator/=(const modint &x) { return *this *= x.inv(); }
    modint pow(unsigned long long n) const { modint x = *this, r(1); while (n) { if (n&1) r *= x; x *= x; n>>=1; } return r; }
    modint inv() const { return pow(mod - 2); }
    friend modint operator+(const modint &a, const modint &b) { return modint(a) += b; }
    friend modint operator-(const modint &a, const modint &b) { return modint(a) -= b; }
    friend modint operator*(const modint &a, const modint &b) { return modint(a) *= b; }
    friend modint operator/(const modint &a, const modint &b) { return modint(a) /= b; }
};

using mint = modint<mod>;

template <unsigned ntt_mod, unsigned ntt_root> class NTT {
    using mint = modint<ntt_mod>;
    static const int maxbit = 25;
    mint e[maxbit], ie[maxbit], sum_e[maxbit], sum_ie[maxbit];
public:
    NTT() {
        int cnt = __builtin_ctz(ntt_mod-1);
        mint w = mint(ntt_root).pow((ntt_mod-1)>>cnt), iw = w.inv();
        for (int i = cnt; ~i; i--, w *= w, iw *= iw) e[i] = w, ie[i] = iw;
        w = 1, iw = 1;
        for (int i = 0; i <= cnt-2; i++) {
            sum_e[i] = e[i+2] * w; w *= ie[i+2];
            sum_ie[i] = ie[i+2] * iw; iw *= e[i+2]; 
        }
    }
    void transform(vector<mint> &F, int sing) {
        const int n = F.size();
        int h = 0;
        while ((unsigned)(1<<h) < (unsigned)n) h++;
        if (~sing) {
            for (int i = 0; i < h; i++) {
                mint s = 1;
                for (int j = 0, t = 1<<i, gap = 1<<(h-i-1); j < t; j++) {
                    for (int k = j<<h-i; k < (j<<h-i)+gap; k++) {
                        mint x = F[k], y = F[gap+k] * s;
                        F[k] = x + y, F[gap+k] = x - y;
                    }
                    s *= sum_e[__builtin_ctz(~(unsigned int)j)];
                }
            }
        }
        else {
            for (int i = h-1; ~i; i--) {
                mint s = 1;
                for (int j = 0, t = 1<<i, gap = 1<<(h-i-1); j < t; j++) {
                    for (int k = j<<(h-i); k < (j<<h-i)+gap; k++) {
                        mint x = F[k], y = F[gap+k];
                        F[k] = x + y, F[gap+k] = (x - y) * s;
                    }
                    s *= sum_ie[__builtin_ctz(~(unsigned int)j)];
                }
            }
            mint inv = mint(1<<h).inv();
            for (int i = 0; i < (1<<h); i++) F[i] *= inv;
        }
    }
};

NTT<mod, G> ntt;

struct poly {
    vector<mint> v;
    poly(int n = 1) : v(n) {}
    int size() const { return (int)v.size(); }
    inline void clear() { v.clear(); }
    inline void cut(int len) { if (len < size()) v.resize(static_cast<size_t>(len)); } 
    inline mint& operator[](int i) { return v[i]; }
    poly& operator+=(const poly &a) {
        this->v.resize(max(size(), a.size()));
        for (int i = a.size()-1; ~i; i--) this->v[i] += a.v[i];
        return *this;
    }
    poly& operator-=(const poly &a) {
        this->v.resize(max(size(), a.size()));
        for (int i = a.size()-1; ~i; i--) this->v[i] -= a.v[i];
        return *this;
    }
    poly& operator*=(poly a) {
        int N = size() + a.size() - 1;
        int len = 1;
        while (len < N) len <<= 1;
        this->v.resize(len), a.v.resize(len);
        ntt.transform(this->v, 1), ntt.transform(a.v, 1);
        for (int i = 0; i < len; i++) v[i] *= a[i];
        ntt.transform(this->v, -1);
        this->cut(N);
        return *this;
    }
    poly operator+(const poly &a) { return poly(*this) += a; }
    poly operator-(const poly &a) { return poly(*this) -= a; }
    poly operator*(const poly &a) { return poly(*this) *= a; }
};

template<class T> struct Factorial {
    vector<T> fac, ifac;
public:
    Factorial(int n) : fac(n+1), ifac(n+1) {
        fac[0] = T(1);
        for (int i = 1; i <= n; i++) fac[i] = fac[i-1] * T(i);
        ifac[n] = fac[n].inv();
        for (int i = n-1; ~i; i--) ifac[i] = ifac[i+1] * T(i+1);
    }
    T& operator[](int i) { return i >= 0 ? fac[i] : ifac[-i]; }
    T C(int n, int m) { return fac[n] * ifac[m] * ifac[n-m]; }
};

const int N = 2e5 + 5;
vector<int> g[N];
bitset<N> vis;
poly cnt, tmp;
int siz[N];

int getsiz(int u, int f) {
    siz[u] = 1;
    for (const int &v : g[u]) {
        if (vis[v] || v == f) continue;
        siz[u] += getsiz(v, u);
    }
    return siz[u];
}
int Findcen(int u, const int &s) {
    for (const int &v : g[u]) {
        if (vis[v] || siz[v] > siz[u]) continue;
        else if (siz[v]*2 > s) return Findcen(v, s);
    }
    return u;
}
void dfs(int u, int f, int dep) {
    while (tmp.size() <= dep) tmp.v.emplace_back();
    tmp[dep] += mint(1);
    for (const int &v : g[u])
        if (!vis[v] && v != f)
            dfs(v, u, dep+1);
    
}
void divide(int u) {
    int s = getsiz(u, u);
    u = Findcen(u, s);
    vis[u] = 1;
    poly all;
    all[0] = 1;
    for (const int &v : g[u]) {
        if (vis[v]) continue;
        divide(v);
        tmp.clear();
        dfs(v, v, 1);
        all += tmp;
        cnt -= tmp * tmp;
    }
    cnt += all * all;
    vis[u] = 0;
}

FastIO IO;
#define cin IO
#define cout IO

void solve() {
    int n;
    cin >> n;
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    divide(1);
    Factorial<mint> F(n);
    poly H(n + n);
    mint inv = mint(2).inv();
    for (int i = 0, len = cnt.size(); i < len; i++) cnt[i] *= F[i-1] * inv;
    for (int i = 0; i <= n; i++) H[i] = F[i-n];
    cnt *= H;
    for (int i = 2; i <= n; i++) cout << (cnt[n + i - 1] * F[2-i]).val << '\n'; 
}
int main() {
    //ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    solve();
}
accuracy: 1
time_ms: 830
memory_kb: 43412
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;

const long long mod = 998244353, G = 3, Gi = (mod + 1) / 3;

struct modint {
    long long val;
    modint(long long v = 0) : val(v) {}
    modint& operator+=(const modint &x) { val += x.val; if (val >= mod) val -= mod; return *this; }
    modint& operator-=(const modint &x) { val -= x.val; if (val < 0) val += mod; return *this; }
    modint& operator*=(const modint &x) { val = val * x.val % mod; return *this; }
    friend modint operator+(const modint &x, const modint &y) { return modint(x) += y; }
    friend modint operator-(const modint &x, const modint &y) { return modint(x) -= y; }
    friend modint operator*(const modint &x, const modint &y) { return modint(x) *= y; }
    modint pow(long long n) { modint x = *this, r(1); while (n) { if (n&1) r *= x; x *= x; n>>=1; } return r; }
    modint inv() { return pow(mod-2); }
};

void NTT(vector<modint> &F, int sign) {
    int len = F.size(), L = __lg(len);
    vector<int> rev(len);
    for (int i = 1; i < len; i++) rev[i] = (rev[i>>1]>>1) | ((i&1)<<(L-1));
    for (int i = 0; i < len; i++) if (i < rev[i]) swap(F[i], F[rev[i]]);
    for (int mid = 1; mid < len; mid<<=1) {
        modint wn = modint(sign == 1 ? G : Gi).pow((mod-1) / (mid<<1));
        for (int i = 0; i < len; i += mid<<1) {
            modint w = 1;
            for (int j = 0; j < mid; j++, w *= wn) {
                modint x = F[i+j], y = F[i+j+mid] * w;
                F[i+j] = x + y, F[i+j+mid] = x - y;
            }
        }
    }
    if (sign == -1) {
        modint inv = modint(len).inv();
        for (int i = 0; i < len; i++) F[i] *= inv;
    }
}

struct poly {
    vector<modint> v;
    poly(int n = 1) : v(n) {}
    int size() const { return (int)v.size(); }
    inline void clear() { v.clear(); }
    inline void cut(int len) { if (len < size()) v.resize(static_cast<size_t>(len)); } 
    inline modint& operator[](int i) { return v[i]; }
    poly& operator+=(const poly &a) {
        this->v.resize(max(size(), a.size()));
        for (int i = a.size()-1; ~i; i--) this->v[i] += a.v[i];
        return *this;
    }
    poly& operator-=(const poly &a) {
        this->v.resize(max(size(), a.size()));
        for (int i = a.size()-1; ~i; i--) this->v[i] -= a.v[i];
        return *this;
    }
    poly& operator*=(poly a) {
        int N = size() + a.size() - 1;
        int len = 1;
        while (len < N) len <<= 1;
        this->v.resize(len), a.v.resize(len);
        NTT(this->v, 1), NTT(a.v, 1);
        for (int i = 0; i < len; i++) v[i] *= a[i];
        NTT(this->v, -1);
        this->cut(N);
        return *this;
    }
    poly operator+(const poly &a) { return poly(*this) += a; }
    poly operator-(const poly &a) { return poly(*this) -= a; }
    poly operator*(const poly &a) { return poly(*this) *= a; }
};

struct Factorial {
    vector<modint> fact, ifact;
    Factorial(int n) : fact(n+1), ifact(n+1) {
        fact[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i-1] * modint(i);
        ifact[n] = fact[n].inv();
        for (int i = n-1; ~i; i--) ifact[i] = ifact[i+1] * modint(i+1);
    }
    modint operator[](int i) { return i >= 0 ? fact[i] : ifact[-i]; }
};

const int N = 2e5 + 5;
vector<int> g[N];
bitset<N> vis;
poly cnt, tmp;
int siz[N];

int getsiz(int u, int f) {
    siz[u] = 1;
    for (const int &v : g[u]) {
        if (vis[v] || v == f) continue;
        siz[u] += getsiz(v, u);
    }
    return siz[u];
}
int Findcen(int u, const int &s) {
    for (const int &v : g[u]) {
        if (vis[v] || siz[v] > siz[u]) continue;
        else if (siz[v]*2 > s) return Findcen(v, s);
    }
    return u;
}
void dfs(int u, int f, int dep) {
    while (tmp.size() <= dep) tmp.v.emplace_back();
    tmp[dep] += modint(1);
    for (const int &v : g[u])
        if (!vis[v] && v != f)
            dfs(v, u, dep+1);
    
}
void divide(int u) {
    int s = getsiz(u, u);
    u = Findcen(u, s);
    vis[u] = 1;
    poly all;
    all[0] = 1;
    for (const int &v : g[u]) {
        if (vis[v]) continue;
        divide(v);
        tmp.clear();
        dfs(v, v, 1);
        all += tmp;
        cnt -= tmp * tmp;
    }
    cnt += all * all;
    vis[u] = 0;
}
void solve() {
    int n;
    cin >> n;
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    divide(1);
    Factorial F(n);
    poly H(n + n);
    modint inv = modint(2).inv();
    for (int i = 0, len = cnt.size(); i < len; i++) cnt[i] *= F[i-1] * inv;
    for (int i = 0; i <= n; i++) H[i] = F[i-n];
    cnt *= H;
    for (int i = 2; i <= n; i++) cout << (cnt[n + i - 1] * F[2-i]).val << '\n'; 
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    solve();
}
accuracy: 1
time_ms: 1740
memory_kb: 59604
final_rank: 10

code_snippet: #include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

static const int MOD = 1000000007;
using ll = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max() / 32 * 15 + 208;

class CentroidDecomposition {
    int dfs(int x, int par){
        sz[x] = 1;
        for (auto &&i : G[x]) {
            if(i == par || v[i]) continue;
            sz[x] += dfs(i, x);
        }
        return sz[x];
    }

    int search_centroid(int x, int p, const int mid){
        for (auto &&i : G[x]) {
            if(i == p || v[i]) continue;
            if(sz[i] > mid) return search_centroid(i, x, mid);
        }
        return x;
    }
public:
    int n;
    vector<vector<int>> G, out;
    vector<int> sz, v;
    CentroidDecomposition(int n) : n(n), G(n), out(n), sz(n), v(n) {}
    void add_edge(int l, int r){
        G[l].emplace_back(r);
        G[r].emplace_back(l);
    }
    int get(int x){
        int centroid = search_centroid(x, -1, dfs(x, -1)/2);
        v[centroid] = true;
        for (auto &&i : G[centroid]) {
            if(!v[i]) out[centroid].emplace_back(get(i));
        }
        v[centroid] = false;
        return centroid;
    }
};

constexpr int ntt_mod = 998244353, ntt_root = 3;
// 1012924417 -> 5, 924844033 -> 5
// 998244353  -> 3, 897581057 -> 3
// 645922817  -> 3;
template <u32 M>
struct modint {
    u32 val;
public:
    static modint raw(int v) { modint x; x.val = v; return x; }
    modint() : val(0) {}
    template <class T>
    modint(T v) { ll x = (ll)(v%(ll)(M)); if (x < 0) x += M; val = u32(x); }
    modint(bool v) { val = ((unsigned int)(v) % M); }
    modint& operator++() { val++; if (val == M) val = 0; return *this; }
    modint& operator--() { if (val == 0) val = M; val--; return *this; }
    modint operator++(int) { modint result = *this; ++*this; return result; }
    modint operator--(int) { modint result = *this; --*this; return result; }
    modint& operator+=(const modint& rhs) { val += rhs.val; if (val >= M) val -= M; return *this; }
    modint& operator-=(const modint& rhs) { val -= rhs.val; if (val >= M) val += M; return *this; }
    modint& operator*=(const modint& rhs) { u64 z = val; z *= rhs.val; val = (u32)(z % M); return *this; }
    modint& operator/=(const modint& rhs) { return *this = *this * rhs.inv(); }
    modint operator+() const { return *this; }
    modint operator-() const { return modint() - *this; }
    modint pow(long long n) const { modint x = *this, r = 1; while (n) { if (n & 1) r *= x; x *= x; n >>= 1; } return r; }
    modint inv() const { return pow(M-2); }
    friend modint operator+(const modint& lhs, const modint& rhs) { return modint(lhs) += rhs; }
    friend modint operator-(const modint& lhs, const modint& rhs) { return modint(lhs) -= rhs; }
    friend modint operator*(const modint& lhs, const modint& rhs) { return modint(lhs) *= rhs; }
    friend modint operator/(const modint& lhs, const modint& rhs) { return modint(lhs) /= rhs; }
    friend bool operator==(const modint& lhs, const modint& rhs) { return lhs.val == rhs.val; }
    friend bool operator!=(const modint& lhs, const modint& rhs) { return lhs.val != rhs.val; }
};
using mint = modint<998244353>;

class NTT {
    static constexpr int max_base = 20, maxN = 1 << max_base; // N <= 524288 * 2
    mint sum_e[30], sum_ie[30];
public:
    mint es[30], ies[30];
    NTT() {
        int cnt2 = __builtin_ctz(ntt_mod-1);
        mint e = mint(ntt_root).pow((ntt_mod-1) >> cnt2), ie = e.inv();
        for (int i = cnt2; i >= 0; i--){
            es[i] = e; ies[i] = ie;
            e *= e; ie *= ie;
        }
        mint now = 1, nowi = 1;
        for (int i = 0; i < cnt2 - 2; i++) {
            sum_e[i] = es[i+2] * now; now *= ies[i+2];
            sum_ie[i] = ies[i+2] * nowi; nowi *= es[i+2];
        }
    }

    void transform(vector<mint> &a, int sign){
        const int n = a.size();
        int h = 0;
        while ((1U << h) < (unsigned int)(n)) h++;
        if(!sign){ // fft
            for (int ph = 1; ph <= h; ph++) {
                int w = 1 << (ph-1), p = 1 << (h-ph);
                mint now = 1;
                for (int s = 0; s < w; s++) {
                    int offset = s << (h-ph+1);
                    for (int i = 0; i < p; i++) {
                        auto l = a[i+offset], r = a[i+offset+p]*now;
                        a[i+offset] = l+r, a[i+offset+p] = l-r;
                    }
                    now *= sum_e[__builtin_ctz(~(unsigned int)(s))];
                }
            }
        }else { // ifft
            for (int ph = h; ph >= 1; ph--) {
                int w = 1 << (ph-1), p = 1 << (h-ph);
                mint inow = 1;
                for (int s = 0; s < w; s++) {
                    int offset = s << (h-ph+1);
                    for (int i = 0; i < p; i++) {
                        auto l = a[i+offset], r = a[i+offset+p];
                        a[i+offset] = l+r, a[i+offset+p] = (l-r)*inow;
                    }
                    inow *= sum_ie[__builtin_ctz(~(unsigned int)(s))];
                }
            }
        }
    }
};

NTT ntt;

struct poly {
    vector<mint> v;
    poly() = default;
    explicit poly(int n) : v(n) {};
    explicit poly(vector<mint> vv) : v(std::move(vv)) {};
    int size() const {return (int)v.size(); }
    poly cut(int len){
        if(len < v.size()) v.resize(static_cast<unsigned long>(len));
        return *this;
    }
    inline mint& operator[] (int i) {return v[i]; }
    poly& operator+=(const poly &a) {
        this->v.resize(max(size(), a.size()));
        for (int i = 0; i < a.size(); ++i) this->v[i] += a.v[i];
        return *this;
    }
    poly& operator-=(const poly &a) {
        this->v.resize(max(size(), a.size()));
        for (int i = 0; i < a.size(); ++i) this->v[i] -= a.v[i];
        return *this;
    }
    poly& operator*=(poly a) {
        int N = size()+a.size()-1;
        int sz = 1;
        while(sz < N) sz <<= 1;
        this->v.resize(sz); a.v.resize(sz);
        ntt.transform(this->v, 0); ntt.transform(a.v, 0);
        for(int i = 0; i < sz; ++i) this->v[i] *= a.v[i];
        ntt.transform(this->v, 1);
        this->v.resize(N);
        mint iz = mint(sz).inv();
        for (int i = 0; i < N; i++) this->v[i] *= iz;
        return *this;
    }
    poly& operator/=(const poly &a){ return (*this *= a.inv()); }
    poly operator+(const poly &a) const { return poly(*this) += a; }
    poly operator-(const poly &a) const { return poly(*this) -= a; }
    poly operator*(const poly &a) const { return poly(*this) *= a; }

    poly inv() const {
        int n = size();
        poly r(1);
        r[0] = (this->v[0]).inv();
        for (int k = 1; k < n; k <<= 1) {
            poly ff(2*k);
            for (int i = 0; i < min(k*2, n); ++i) ff[i] = this->v[i];
            poly nr = (r*r*ff).cut(k*2);
            for (int i = 0; i < k; ++i) {
                nr[i] = (r[i]+r[i]-nr[i]);
                nr[i+k] = -nr[i+k];
            }
            r = nr;
        }
        r.v.resize(n);
        return r;
    }
};

class Factorial {
    vector<mint> facts, factinv;
public:
    explicit Factorial(int n) : facts(n+1), factinv(n+1) {
        facts[0] = 1;
        for (int i = 1; i < n+1; ++i) facts[i] = facts[i-1] * mint(i);
        factinv[n] = facts[n].inv();
        for (int i = n-1; i >= 0; --i) factinv[i] = factinv[i+1] * mint(i+1);
    }
    mint fact(int k) const {
        if(k >= 0) return facts[k]; else return factinv[-k];
    }
    mint operator[](const int &k) const {
        if(k >= 0) return facts[k]; else return factinv[-k];
    }
    mint C(int p, int q) const {
        if(q < 0 || p < q) return 0;
        return facts[p] * factinv[q] * factinv[p-q];
    }
    mint P(int p, int q) const {
        if(q < 0 || p < q) return 0;
        return facts[p] * factinv[p-q];
    }
    mint H(int p, int q) const {
        if(p < 0 || q < 0) return 0;
        return q == 0 ? 1 : C(p+q-1, q);
    }
};


int main() {
    int n;
    cin >> n;
    CentroidDecomposition G(n);
    for (int i = 0; i < n-1; ++i) {
        int u, v;
        scanf("%d %d", &u, &v);
        u--; v--;
        G.add_edge(u, v);
    }
    int root = G.get(0);
    vector<int> bad(n);
    poly val;
    auto dfs = [&](int centroid, auto &&f) -> void {
        bad[centroid] = 1;
        poly all(1);
        all[0] = 1;
        for (auto &&i : G.G[centroid]) {
            if(bad[i]) continue;
            poly a;
            queue<tuple<int, int, int>> Q;
            Q.emplace(i, centroid, 1);
            while(!Q.empty()){
                auto [x, par, dep] = Q.front(); Q.pop();
                while(a.size() <= dep) a.v.emplace_back();
                while(all.size() <= dep) all.v.emplace_back();
                a[dep]++; all[dep]++;
                for (auto &&y : G.G[x]) {
                    if(y != par && !bad[y]) Q.emplace(y, x, dep+1);
                }
            }
            val -= a * a;
        }
        val += all * all;
        for (auto &&i : G.out[centroid]) f(i, f);
    };
    dfs(root, dfs);
    Factorial f(n);
    for (int i = 1; i < val.size(); ++i) {
        val[i-1] = val[i]*mint(499122177)*f[i-1];
    }
    val.v.pop_back();
    poly fact(n);
    for (int i = 0; i < n; ++i) {
        fact[i] = f[-(n-1-i)];
    }
    val *= fact;
    for (int i = 0; i < n-1; ++i) {
        if(n+i < val.size()+1) printf("%d\n", (val[n-1+i]*f[-i]).val);
        else printf("%d\n", 0);
    }
    return 0;
}
accuracy: 1
time_ms: 660
memory_kb: 49972
final_rank: 6

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <iomanip>
#include <queue>
#include <string>
#include <map>
#include <fstream>
#include <cassert>
#include <stack>
#include <climits>
#include <array>
#include <unordered_set>
#include <unordered_map>
#include <memory>
#include <functional>
#include <cfloat>
#include <numeric>
#include <random>
#include <sstream>
#include <bitset>
using namespace std;
constexpr int MOD = 998244353;

static std::array<int, 20> primitive_root{ 0, 998244352, 911660635, 372528824, 69212480, 617152567, 926351381, 553154607, 835711138, 476870429, 578036328, 579795361, 533803820, 843506711, 57929585, 670729537, 341689982, 178698007, 3411409, 1847 };
static std::array<int, 20> reverse_root{ 0, 998244352, 86583718, 509520358, 661054123, 134322755, 77113778, 871797313, 179557483, 757331369, 195869564, 981311075, 229697978, 936970679, 760640816, 113194219, 815372449, 798661279, 53782855, 510742238 };

int log2ceil(int size) {
	int log{ 0 };
	while (size > 1) {
		size = (size + 1) >> 1;
		++log;
	}
	return log;
}
long long int power(long long int base, int exp) {
	long long int result{ 1 };
	while (exp > 0) {
		if (exp & 1) {
			result = result * base % MOD;
		}
		base = (base * base) % MOD;
		exp >>= 1;
	}
	return result;
}
std::vector<int> ft(std::vector<int> a, const bool inverse = false) {
	const auto log = log2ceil(a.size());
	for (auto i = a.size(); i < (1 << log); ++i) a.push_back(0);
	std::vector<int> result(a.size(), 0);
	for (auto i = 0; i < result.size(); ++i) {
		const auto root = inverse ? power(reverse_root[log], i) : power(primitive_root[log], i);
		auto r = 1LL;
		for (auto j = 0; j < a.size(); ++j){
			result[i] = (result[i] + a[j] * r) % MOD;
			r = (r * root) % MOD;
		}
		result[i] %= MOD;
	}
	if (inverse) {
		const auto rev = power(a.size(), MOD - 2);
		for (auto& n : result) n = (n * rev) % MOD;
	}
	return result;
}
std::vector<int> fft(std::vector<int> a, const bool inverse = false) {
	const auto log = log2ceil(a.size());
	a.reserve(1 << log);
	for (auto i = a.size(); i < (1 << log); ++i) {
		a.push_back(0);
	}
	for (auto i = 0; i < a.size(); ++i) {
		int rev{ 0 };
		for (auto j = 0; j < log; ++j) {
			rev <<= 1;
			rev += (i >> j) & 1;
		}
		if (i < rev) std::swap(a[i], a[rev]);
	}
	for (auto d = 0; (1 << d) < a.size(); ++d) {
		const auto width = 1 << d;
		auto root = 1LL;
		const auto half = inverse ? reverse_root[1] : primitive_root[1];
		const auto w = inverse ? reverse_root[d + 1] : primitive_root[d + 1];
		for (auto i = 0; i < width; ++i) {
			for (auto j = 0; j < a.size(); j += width << 1) {
				const auto pos = a[i + j + width] * root % MOD;
				a[i + j + width] = (a[i + j] + pos * half % MOD) % MOD;
				a[i + j] = (a[i + j] + pos) % MOD;
			}
			root = root * w % MOD;
		}
	}
	if (inverse) {
		const auto rev = power(a.size(), MOD - 2);
		for (auto& x : a) x = (x * rev) % MOD;
	}
	return a;
}
std::vector<int> fold_fft(std::vector<int> a, std::vector<int> b) {
	const auto result_size = a.size() + b.size() - 1;
	const auto log = log2ceil(result_size);
	for (auto i = a.size(); i < (1 << log); ++i) {
		a.push_back(0);
	}
	const auto a_fft = fft(std::move(a));
	for (auto i = b.size(); i < (1 << log); ++i) {
		b.push_back(0);
	}
	const auto b_fft = fft(std::move(b));
	std::vector<int> c(1 << log);
	for (auto i = 0; i < c.size(); ++i) {
		c[i] = (long long int)a_fft[i] * b_fft[i] % MOD;
	}
	auto result = fft(std::move(c), true);
	result.resize(result_size);
	return result;
}

class Tree {
	std::vector<std::vector<int>> nodes;
	std::vector<int> tree_size;
	std::vector<bool> used;
	std::vector<int> sum_route;
	std::vector<int> sum_path;
	std::vector<int> history;
	int call{ 0 };
	std::vector<int> calc_route_count(const int root) {
		std::queue<int> queue; queue.push(root);
		std::vector<int> result;
		history[root] = ++call;
		while (!queue.empty()) {
			result.push_back(queue.size());
			for (auto i = 0; i < result.back(); ++i) {
				const auto top = queue.front(); queue.pop();
				for (const auto child : nodes[top]) {
					if (used[child]) continue;
					if (history[child] == call) continue;
					history[child] = call;
					queue.push(child);
				}
			}
		}
		return result;
	}
	void calc_subtree(const int node) {
		const auto center = find_center(node);
		used[center] = true;
		std::vector<std::vector<int>> children;
		sum_path.clear();
		for (const auto child : nodes[center]) {
			if (used[child]) continue;
			const auto count = calc_route_count(child);
			if (sum_path.empty()) {
				sum_path = count;
			}
			else {
				const auto fold = fold_fft(sum_path, count);
				for (auto i = 0; i < fold.size(); ++i) {
					sum_route[i + 2] = (sum_route[i + 2] + fold[i]) % MOD;
				}
				if (count.size() > sum_path.size()) {
					for (auto i = sum_path.size(); i < count.size(); ++i) sum_path.push_back(0);
				}
				for (auto i = 0; i < count.size(); ++i) sum_path[i] = (sum_path[i] + count[i]) % MOD;
			}
		}
		for (auto i = 0; i < sum_path.size(); ++i) {
			sum_route[i + 1] = (sum_route[i + 1] + sum_path[i]) % MOD;
		}
		for (const auto child : nodes[center]) {
			if (used[child]) continue;
			calc_subtree(child);
		}
	}
	int find_center(const int node) {
		std::stack<std::pair<int, int>> stack, reverse;
		tree_size[node] = 1;
		for (const auto child : nodes[node]) {
			if (used[child]) {
				tree_size[child] = 0;
				continue;
			}
			stack.emplace(node, child);
		}
		while (!stack.empty()) {
			const auto [parent, current] = stack.top(); stack.pop();
			reverse.emplace(parent, current);
			tree_size[current] = 1;
			for (const auto child : nodes[current]) {
				if (parent == child) continue;
				if (used[child]) {
					tree_size[child] = 0;
					continue;
				}
				stack.emplace(current, child);
			}
		}
		while (!reverse.empty()) {
			const auto [parent, child] = reverse.top(); reverse.pop();
			tree_size[parent] += tree_size[child];
		}
		const auto full_size = tree_size[node];
		int center = node;
		while (std::any_of(nodes[center].begin(), nodes[center].end(), [&](const int i) {return (tree_size[i] << 1) > full_size; })) {
			const auto max = *std::max_element(nodes[center].begin(), nodes[center].end(), [&](const int i, const int j) {return tree_size[i] < tree_size[j]; });
			tree_size[center] = full_size - tree_size[max];
			tree_size[max] = full_size;
			center = max;
		}
		return center;
	}
public:
	Tree(const std::vector<std::vector<int>>& nodes) : nodes{ nodes }, tree_size(nodes.size(), 0), used(nodes.size(), false), sum_route(nodes.size() + 1, 0), history(nodes.size(), -1) {
		calc_subtree(0);
	}
	const std::vector<int>& route_count() const {
		return sum_route;
	}
};
int main() {
	int n; std::cin >> n;
	std::vector<std::vector<int>> cotage(n);
	for (auto i = 1; i < n; ++i) {
		int s, t; std::cin >> s >> t; --s; --t;
		cotage[s].push_back(t);
		cotage[t].push_back(s);
	}
	Tree tree(cotage);
	std::vector<int> factorial(n + 1, 1), div(n + 1, 1), inverse(n + 1, 1);
	for (auto i = 2; i < factorial.size(); ++i) {
		factorial[i] = ((long long int)i * factorial[i - 1]) % MOD;
		div[i] = (long long int)(MOD - MOD / i) * div[MOD % i] % MOD;
		inverse[i] = (long long int)div[i] * inverse[i - 1] % MOD;
	}
	const auto route_count = tree.route_count();
	std::vector<int> right(n + 1, 0);
	for (auto i = 1; i < right.size(); ++i) {
		right[i] = (long long int)factorial[n - i] * route_count[n - i + 1] % MOD;
	}
	const auto res = fold_fft(inverse, right);
	for (auto i = 2; i <= n; ++i) {
		std::cout << ((long long int)res[n - i + 2] * inverse[i - 2]) % MOD << '\n';
	}
}
accuracy: 1
time_ms: 720
memory_kb: 40948
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Centroid{
  vector<int> sz,dead;
  vector< vector<int> > G;
  Centroid(int n):sz(n,1),dead(n,0),G(n){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  int dfs(int v,int p){
    sz[v]=1;
    for(int u:G[v])
      if(u!=p and !dead[u]) sz[v]+=dfs(u,v);
    return sz[v];
  }

  void find(int v,int p,int tmp,vector<int> &cs) {
    int ok=1;
    for (int u:G[v]){
      if(u==p or dead[u]) continue;
      find(u,v,tmp,cs);
      ok&=(sz[u]<=tmp/2);
    }
    ok&=(tmp-sz[v]<=tmp/2);
    if(ok) cs.emplace_back(v);
  }

  vector<int> build(int r) {
    int tmp=dfs(r,-1);
    vector<int> cs;
    find(r,-1,tmp,cs);
    return cs;
  }

  const vector<int>& operator[](int k)const{return G[k];}
  void disable(int v){dead[v]=1;}
  void  enable(int v){dead[v]=0;}
  int alive(int v){return !dead[v];}
};

template<typename F>
struct FixPoint : F{
  FixPoint(F&& f):F(forward<F>(f)){}
  template<typename... Args>
  decltype(auto) operator()(Args&&... args) const{
    return F::operator()(*this,forward<Args>(args)...);
  }
};

template<typename F>
inline decltype(auto) MFP(F&& f){
  return FixPoint<F>{forward<F>(f)};
}


template<typename T, T MOD = 1000000007>
struct Mint{
  static constexpr T mod = MOD;
  T v;
  Mint():v(0){}
  Mint(signed v):v(v){}
  Mint(long long t){v=t%MOD;if(v<0) v+=MOD;}

  Mint pow(long long k){
    Mint res(1),tmp(v);
    while(k){
      if(k&1) res*=tmp;
      tmp*=tmp;
      k>>=1;
    }
    return res;
  }

  static Mint add_identity(){return Mint(0);}
  static Mint mul_identity(){return Mint(1);}

  Mint inv(){return pow(MOD-2);}

  Mint& operator+=(Mint a){v+=a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator-=(Mint a){v+=MOD-a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator*=(Mint a){v=1LL*v*a.v%MOD;return *this;}
  Mint& operator/=(Mint a){return (*this)*=a.inv();}

  Mint operator+(Mint a) const{return Mint(v)+=a;}
  Mint operator-(Mint a) const{return Mint(v)-=a;}
  Mint operator*(Mint a) const{return Mint(v)*=a;}
  Mint operator/(Mint a) const{return Mint(v)/=a;}

  Mint operator-() const{return v?Mint(MOD-v):Mint(v);}

  bool operator==(const Mint a)const{return v==a.v;}
  bool operator!=(const Mint a)const{return v!=a.v;}
  bool operator <(const Mint a)const{return v <a.v;}

  static Mint comb(long long n,int k){
    Mint num(1),dom(1);
    for(int i=0;i<k;i++){
      num*=Mint(n-i);
      dom*=Mint(i+1);
    }
    return num/dom;
  }
};
template<typename T, T MOD> constexpr T Mint<T, MOD>::mod;
template<typename T, T MOD>
ostream& operator<<(ostream &os,Mint<T, MOD> m){os<<m.v;return os;}


constexpr int bmds(int x){
  const int v[] = {1012924417, 924844033, 998244353,
                   897581057, 645922817};
  return v[x];
}
constexpr int brts(int x){
  const int v[] = {5, 5, 3, 3, 3};
  return v[x];
}

template<int X>
struct NTT{
  static constexpr int md = bmds(X);
  static constexpr int rt = brts(X);
  using M = Mint<int, md>;
  vector< vector<M> > rts,rrts;

  void ensure_base(int n){
    if((int)rts.size()>=n) return;
    rts.resize(n);rrts.resize(n);
    for(int i=1;i<n;i<<=1){
      if(!rts[i].empty()) continue;
      M w=M(rt).pow((md-1)/(i<<1));
      M rw=w.inv();
      rts[i].resize(i);rrts[i].resize(i);
      rts[i][0]=M(1);rrts[i][0]=M(1);
      for(int k=1;k<i;k++){
        rts[i][k]=rts[i][k-1]*w;
        rrts[i][k]=rrts[i][k-1]*rw;
      }
    }
  }

  void ntt(vector<M> &as,bool f){
    int n=as.size();
    assert((n&(n-1))==0);
    ensure_base(n);

    for(int i=0,j=1;j+1<n;j++){
      for(int k=n>>1;k>(i^=k);k>>=1);
      if(i>j) swap(as[i],as[j]);
    }

    for(int i=1;i<n;i<<=1){
      for(int j=0;j<n;j+=i*2){
        for(int k=0;k<i;k++){
          M z=as[i+j+k]*(f?rrts[i][k]:rts[i][k]);
          as[i+j+k]=as[j+k]-z;
          as[j+k]+=z;
        }
      }
    }

    if(f){
      M tmp=M(n).inv();
      for(int i=0;i<n;i++) as[i]*=tmp;
    }
  }

  vector<M> multiply(vector<M> as,vector<M> bs){
    int need=as.size()+bs.size()-1;
    int sz=1;
    while(sz<need) sz<<=1;
    as.resize(sz,M(0));
    bs.resize(sz,M(0));

    ntt(as,0);ntt(bs,0);
    for(int i=0;i<sz;i++) as[i]*=bs[i];
    ntt(as,1);

    as.resize(need);
    return as;
  }

  vector<int> multiply(vector<int> as,vector<int> bs){
    vector<M> am(as.size()),bm(bs.size());
    for(int i=0;i<(int)am.size();i++) am[i]=M(as[i]);
    for(int i=0;i<(int)bm.size();i++) bm[i]=M(bs[i]);
    vector<M> cm=multiply(am,bm);
    vector<int> cs(cm.size());
    for(int i=0;i<(int)cs.size();i++) cs[i]=cm[i].v;
    return cs;
  }
};
template<int X> constexpr int NTT<X>::md;
template<int X> constexpr int NTT<X>::rt;


template<typename M_>
class Enumeration{
  using M = M_;
protected:
  static vector<M> fact,finv,invs;
public:
  static void init(int n){
    n=min<decltype(M::mod)>(n,M::mod-1);

    int m=fact.size();
    if(n<m) return;

    fact.resize(n+1,1);
    finv.resize(n+1,1);
    invs.resize(n+1,1);

    if(m==0) m=1;
    for(int i=m;i<=n;i++) fact[i]=fact[i-1]*M(i);
    finv[n]=M(1)/fact[n];
    for(int i=n;i>=m;i--) finv[i-1]=finv[i]*M(i);
    for(int i=m;i<=n;i++) invs[i]=finv[i]*fact[i-1];
  }

  static M Fact(int n){
    init(n);
    return fact[n];
  }
  static M Finv(int n){
    init(n);
    return finv[n];
  }
  static M Invs(int n){
    init(n);
    return invs[n];
  }

  static M C(int n,int k){
    if(n<k or k<0) return M(0);
    init(n);
    return fact[n]*finv[n-k]*finv[k];
  }

  static M P(int n,int k){
    if(n<k or k<0) return M(0);
    init(n);
    return fact[n]*finv[n-k];
  }

  // put n identical balls into k distinct boxes
  static M H(int n,int k){
    if(n<0 or k<0) return M(0);
    if(!n and !k) return M(1);
    init(n+k);
    return C(n+k-1,n);
  }
};
template<typename M>
vector<M> Enumeration<M>::fact=vector<M>();
template<typename M>
vector<M> Enumeration<M>::finv=vector<M>();
template<typename M>
vector<M> Enumeration<M>::invs=vector<M>();

//INSERT ABOVE HERE

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  NTT<2> ntt;
  using M = decltype(ntt)::M;
  using E = Enumeration<M>;
  E::init(1e6);

  int n;
  cin>>n;
  Centroid G(n);
  for(int i=1;i<n;i++){
    int a,b;
    cin>>a>>b;
    a--;b--;
    G.add_edge(a,b);
  }

  queue<int> que;
  que.emplace(G.build(0)[0]);

  vector<M> ans(n,0);
  while(!que.empty()){
    int r=que.front();que.pop();
    vector<M> cnt;
    cnt.emplace_back(1);
    for(int c:G[r]){
      if(!G.alive(c)) continue;
      vector<M> num;
      MFP([&](auto dfs,int v,int p,int d)->void{
        while((int)cnt.size()<=d)
          cnt.emplace_back(0);
        while((int)num.size()<=d)
          num.emplace_back(0);
        cnt[d]+=M(1);
        num[d]+=M(1);
        for(int u:G[v]){
          if(u==p or !G.alive(u)) continue;
          dfs(u,v,d+1);
        }
      })(c,r,1);
      auto ns=ntt.multiply(num,num);
      for(int i=0;i<(int)min(ans.size(),ns.size());i++) ans[i]-=ns[i];
    }
    auto cs=ntt.multiply(cnt,cnt);
    for(int i=0;i<(int)min(ans.size(),cs.size());i++) ans[i]+=cs[i];

    G.disable(r);
    for(int c:G[r])
      if(G.alive(c))
        que.emplace(G.build(c)[0]);
  }

  ans.resize(n+3);
  for(int i=0;i<n;i++) ans[i]/=M(2);
  // for(int i=0;i<n;i++) cout<<ans[i]<<endl;

  using Poly = vector<M>;
  Poly fs(n+1);
  for(int i=0;i<=n;i++) fs[i]=ans[n+1-i]*E::Fact(n-i);

  Poly gs(n+1);
  for(int i=0;i<=n;i++) gs[i]=E::Finv(i);

  // for(int i=0;i<=n;i++) cout<<fs[i]<<' '<<gs[i]<<endl;

  Poly hs=ntt.multiply(fs,gs);
  for(int i=0;i<=n;i++) hs[i]*=E::Finv(n-i);

  for(int i=0;i+1<n;i++)
    cout<<hs[n-i]<<'\n';
  return 0;
}
accuracy: 1
time_ms: 820
memory_kb: 87076
final_rank: 11