Problem:
Commuting Route
In the town of Aizu, where PCK lives, there are N points and $N-1$ roads connecting each point. Each point is numbered from $1$ to $N$, and all roads can be traveled in both directions. Also, from any point, you can reach other points by taking some paths.
PCK, the CEO of IZUA Corporation, decides to change his route to work every day as a routine work to add a change to his daily life.
PCK commutes to work by a route that satisfies the following conditions.
It is a route that departs from the nearest point $u$ at home and arrives at the nearest point $v$ at work.
The route passes through $u$ and $v$ exactly once on departure and arrival, respectively.
Each point on the path except $u$ and $v$ is passed at most twice.
Each path on the route is traversed up to two times.
PCK is considering relocating his home and office and wants to know how many different ways he can enjoy his commute after the move.
We are given the number of points, information about the roads that directly connect the points and the nearest point $u$ to our home and $v$ to our office after the relocation. However, several pairs of $u$ and $v$ are given as questions. For each question, create a program to find the number of commuting routes.
Input
Input is given in the following format.
$N$
$s_1$ $t_1$
$s_2$ $t_2$
:
$s_{N-1}$ $t_{N-1}$
$Q$
$u_1$ $v_1$
$u_2$ $v_2$
:
$u_Q$ $v_Q$
On the first line, the number of points $N$ ($2 \leq N \leq 100,000$) is given. In the following $N-1$ line, the information about the road that directly connects the two points is given. $s_i$ and $t_i$ ($1 \leq s_i < t_i \leq N$) are the numbers of the two points connected by the $i$th path. However, for any two points, no more than one road connects them directly. The number of questions $Q$ ($1 \leq Q\leq 100,000$) is given in the following line. The subsequent $Q$ line is given two integers $u_i$ and $v_i$ ($1 \leq u_i < v_i \leq N$) representing each question.
Output
For each question, output the remainder of the number of commuting routes divided by 998,244,353 on one line.
Sample Input and Output
Sample Input
4
1 2
2 3
2 4
2
1 2
1 3
Sample Output
1
2

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
// #include<atcoder/all>
// using mint = atcoder::modint998244353;
using ld = long double;
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define rep(i,n) for(int i=0;i<(int)(n);++i)
template<typename T>bool chmin(T&a,T b){return b<a?(a=b,1):0;}
template<typename T>bool chmax(T&a,T b){return b>a?(a=b,1):0;}


struct LCA{
    int N;
    vector<vector<int>> G,parent;
    vector<int> depth;
    LCA(const vector<vector<int>> &G_, int root=0):N(G_.size()), G(G_), depth(G_.size())
    {
        int lg = 0;
        while((1<<lg)+1<N)lg++;
        parent.assign(lg+1, vector<int>(N));

        dfs(root,-1,0);
        for(int k=1;k<(int)parent.size();k++)
        {
            for(int i=0;i<N;i++)
            {
                if(parent[k-1][i]==-1)parent[k][i]=-1;
                else parent[k][i]=parent[k-1][parent[k-1][i]];
            }
        }

    }
    void dfs(int u, int p, int d)
    {
        depth[u]=d;
        parent[0][u]=p;
        for(int v:G[u]) if(v!=p) dfs(v, u, d+1);
    }
    int lca(int u, int v)
    {
        if(depth[u]>depth[v])swap(u,v);
        for(int k=0;k<(int)parent.size();k++) if((depth[v]-depth[u])>>k&1) v=parent[k][v];
        if(u==v) return u;
        for(int k=parent.size();k--;) if(parent[k][u]!=parent[k][v])
        {
            u=parent[k][u];
            v=parent[k][v];
        }
        return parent[0][u];
    }
    int kth_ancestor(int v, int k){
        rep(i,parent.size()){
            if(k&1){
                v=parent[i][v];
            }
            k>>=1;
        }
        return v;
    }
};

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

public:
  u64 a;

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

using mint=modint<998244353>;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int N;
    cin>>N;
    vector<vector<int>> G(N);
    rep(i,N-1){
        int s,t;
        cin>>s>>t;
        s--;t--;
        G[s].push_back(t);
        G[t].push_back(s);
    }
    LCA lca(G);


    vector<int> sz(N,0);
    auto dfs_sz=[&](auto self, int v, int p)->void {
        sz[v]=1;
        for(int e: G[v]){
            if(e==p) continue;
            self(self,e,v);
            sz[v]+=sz[e];
        }

    };
    dfs_sz(dfs_sz, 0, -1);

    vector<mint> m(N,1);
    auto dfs_mul=[&](auto self, int v, int p)->void {
        for(int e: G[v]){
            if(e==p) continue;
            m[e]=m[v]*(sz[v]-sz[e]);
            self(self, e, v);
        }
    };
    dfs_mul(dfs_mul, 0, -1);
    int Q;
    cin>>Q;
    while(Q--){
        int u,v;
        cin>>u>>v;
        u--;v--;
        int l=lca.lca(u,v);
        mint ans=1;
        if(l==v) swap(u,v);
        if(l==u){
            ans*=m[v];
            int a=lca.kth_ancestor(v, lca.depth[v]-lca.depth[l]-1);
            ans/=m[a];
        }
        else{
            ans*=m[u]*m[v];
            int a=lca.kth_ancestor(u, lca.depth[u]-lca.depth[l]-1);
            int b=lca.kth_ancestor(v, lca.depth[v]-lca.depth[l]-1);
            ans/=m[a];
            ans/=m[b];
            ans*=(N-sz[a]-sz[b]);
        }

        cout<<ans.value()<<"\n";
    }
}
accuracy: 1
time_ms: 70
memory_kb: 27832
final_rank: 7

code_snippet: // AOJ #465 Commuting Route
// 2025.2.19

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;
const int NMAX = 100005;

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

int Cin() {  // 整数の入力
	int n = 0, 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');
}

int N;
vector<int> adj[NMAX];
int parent[NMAX], depth[NMAX], subSize[NMAX];
int upTable[20][NMAX];
 
void dfs(int v, int p) {
    parent[v] = p;
    depth[v] = (p == -1 ? 0 : depth[p] + 1);
    subSize[v] = 1;
    for (int nv : adj[v]) {
        if(nv == p) continue;
        dfs(nv, v);
        subSize[v] += subSize[nv];
    }
}
 
void buildLCA() {
    for (int v = 0; v < N; v++) upTable[0][v] = parent[v];
    for (int k = 1; k < 20; k++){
        for (int v = 0; v < N; v++){
            int mid = upTable[k-1][v];
            upTable[k][v] = (mid == -1 ? -1 : upTable[k-1][mid]);
        }
    }
}
 
int LCA(int a, int b) {
    if(depth[a] < depth[b]) swap(a, b);
    int d = depth[a] - depth[b];
    for (int k = 0; k < 20; k++){
        if(d & (1 << k)) a = upTable[k][a];
    }
    if(a == b) return a;
    for (int k = 19; k >= 0; k--){
        if(upTable[k][a] != upTable[k][b]){
            a = upTable[k][a];
            b = upTable[k][b];
        }
    }
    return parent[a];
}
 
int lift(int u, int d) {
    for (int k = 0; k < 20; k++){
        if(d & (1 << k)){
            u = upTable[k][u];
            if(u == -1) break;
        }
    }
    return u;
}
 
ll modinv(ll a, ll m = MOD) {
    ll res = 1, e = a, p = m - 2;
    while(p){
        if(p & 1) res = (res * e) % m;
        e = (e * e) % m;
        p >>= 1;
    }
    return res;
}
 
vector<ll> parProd; 
vector<ll> diff;
 
void calcDiffAndParProd(int v, int p) {
    if(v == 0) {
        diff[v] = 1;
        parProd[v] = 1;
    } else {
        diff[v] = ((ll) subSize[p] - subSize[v]) % MOD;
        if(diff[v] < 0) diff[v] += MOD;
        parProd[v] = (parProd[p] * diff[v]) % MOD;
    }
    for (int nv : adj[v]) {
        if(nv == p) continue;
        calcDiffAndParProd(nv, v);
    }
}
 
int main() {
    N = Cin();
    for (int i = 0; i < N-1; i++){
        int u = Cin()-1, v = Cin()-1;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
 
    dfs(0, -1);
    buildLCA();
    diff.resize(N); parProd.resize(N);
    calcDiffAndParProd(0, -1);
 
    int Q = Cin();
    while(Q--){
        int uu = Cin()-1, vv = Cin()-1;
        if(uu == vv){
            Cout(1);
            continue;
        }
 
        int l = LCA(uu, vv);
 
        ll prodUp = 1;
        if(uu != l){
            int d = depth[uu] - depth[l];
            if(d >= 2){
                int cu = lift(uu, d - 1);
                prodUp = (parProd[uu] * modinv(parProd[cu])) % MOD;
            }
        }
 
        ll prodDown = 1;
        if(vv != l){
            int d = depth[vv] - depth[l];
            if(d >= 2){
                int cv = lift(vv, d - 1);
                prodDown = (parProd[vv] * modinv(parProd[cv])) % MOD;
            }
        }
 
        ll ans = (prodUp * prodDown) % MOD;
 
        if(uu != l && vv != l){
            int d1 = depth[uu] - depth[l];
            int d2 = depth[vv] - depth[l];
            int cu = lift(uu, d1 - 1);
            int cv = lift(vv, d2 - 1);
            ll factorL = (1 + (((ll) (N - 1) - subSize[cu] - subSize[cv]) % MOD)) % MOD;
            if(factorL < 0) factorL += MOD;
            ans = (ans * factorL) % MOD;
        }
        Cout(ans);
    }
    return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 25104
final_rank: 4

code_snippet: // AOJ #465 Commuting Route
// 2025.2.19

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;
const int NMAX = 100005;
 
int N;
vector<int> adj[NMAX];
int parent[NMAX], depth[NMAX], subSize[NMAX];
int upTable[20][NMAX];
 
void dfs(int v, int p) {
    parent[v] = p;
    depth[v] = (p == -1 ? 0 : depth[p] + 1);
    subSize[v] = 1;
    for (int nv : adj[v]) {
        if(nv == p) continue;
        dfs(nv, v);
        subSize[v] += subSize[nv];
    }
}
 
void buildLCA() {
    for (int v = 0; v < N; v++) upTable[0][v] = parent[v];
    for (int k = 1; k < 20; k++){
        for (int v = 0; v < N; v++){
            int mid = upTable[k-1][v];
            upTable[k][v] = (mid == -1 ? -1 : upTable[k-1][mid]);
        }
    }
}
 
int LCA(int a, int b) {
    if(depth[a] < depth[b]) swap(a, b);
    int d = depth[a] - depth[b];
    for (int k = 0; k < 20; k++){
        if(d & (1 << k)) a = upTable[k][a];
    }
    if(a == b) return a;
    for (int k = 19; k >= 0; k--){
        if(upTable[k][a] != upTable[k][b]){
            a = upTable[k][a];
            b = upTable[k][b];
        }
    }
    return parent[a];
}
 
int lift(int u, int d) {
    for (int k = 0; k < 20; k++){
        if(d & (1 << k)){
            u = upTable[k][u];
            if(u == -1) break;
        }
    }
    return u;
}
 
ll modinv(ll a, ll m = MOD) {
    ll res = 1, e = a, p = m - 2;
    while(p){
        if(p & 1) res = (res * e) % m;
        e = (e * e) % m;
        p >>= 1;
    }
    return res;
}
 
vector<ll> parProd; 
vector<ll> diff;
 
void calcDiffAndParProd(int v, int p) {
    if(v == 0) {
        diff[v] = 1;
        parProd[v] = 1;
    } else {
        diff[v] = ((ll) subSize[p] - subSize[v]) % MOD;
        if(diff[v] < 0) diff[v] += MOD;
        parProd[v] = (parProd[p] * diff[v]) % MOD;
    }
    for (int nv : adj[v]) {
        if(nv == p) continue;
        calcDiffAndParProd(nv, v);
    }
}
 
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
 
    cin >> N;
    for (int i = 0; i < N-1; i++){
        int u, v;
        cin >> u >> v;
        u--; v--;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
 
    dfs(0, -1);
    buildLCA();
    diff.resize(N); parProd.resize(N);
    calcDiffAndParProd(0, -1);
 
    int Q; cin >> Q;
    while(Q--){
        int uu, vv;
        cin >> uu >> vv;
        uu--; vv--;
        if(uu == vv){
            cout << 1 << endl;
            continue;
        }
 
        int l = LCA(uu, vv);
 
        ll prodUp = 1;
        if(uu != l){
            int d = depth[uu] - depth[l];
            if(d >= 2){
                int cu = lift(uu, d - 1);
                prodUp = (parProd[uu] * modinv(parProd[cu])) % MOD;
            }
        }
 
        ll prodDown = 1;
        if(vv != l){
            int d = depth[vv] - depth[l];
            if(d >= 2){
                int cv = lift(vv, d - 1);
                prodDown = (parProd[vv] * modinv(parProd[cv])) % MOD;
            }
        }
 
        ll ans = (prodUp * prodDown) % MOD;
 
        if(uu != l && vv != l){
            int d1 = depth[uu] - depth[l];
            int d2 = depth[vv] - depth[l];
            int cu = lift(uu, d1 - 1);
            int cv = lift(vv, d2 - 1);
            ll factorL = (1 + (((ll) (N - 1) - subSize[cu] - subSize[cv]) % MOD)) % MOD;
            if(factorL < 0) factorL += MOD;
            ans = (ans * factorL) % MOD;
        }
        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 25244
final_rank: 9

code_snippet: #line 1 "0465.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/0465"

#line 2 "/home/zawatin/compro/cp-documentation/Src/Template/IOSetting.hpp"

#line 2 "/home/zawatin/compro/cp-documentation/Src/Template/TypeAlias.hpp"

#include <cstdint>
#include <cstddef>

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
#line 4 "/home/zawatin/compro/cp-documentation/Src/Template/IOSetting.hpp"

#include <iostream>
#include <iomanip>

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
#line 2 "/home/zawatin/compro/cp-documentation/Src/Graph/Tree/HeavyLightDecomposition.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/Graph/Tree/HeavyLightDecomposition.hpp"

#include <algorithm>
#include <cassert>
#include <cmath>
#include <limits>
#include <utility>
#include <vector>

namespace zawa {

template <class V>
class HeavyLightDecomposition {
public:

    static constexpr V Invalid() noexcept {
        return INVALID;
    }

    HeavyLightDecomposition() = default;

    HeavyLightDecomposition(std::vector<std::vector<V>> T, V root = 0u) 
        : n_{T.size()}, par_(n_), top_(n_), idx_(n_), 
        inv_(n_), size_(n_, usize{1}), dep_(n_) {

            auto dfs1{[&](auto dfs, V v, V p, usize d) -> usize {
                par_[v] = p;
                dep_[v] = d;
                if (p != INVALID) {
                    for (u32 i{} ; i + 1 < T[v].size() ; i++) if (T[v][i] == p) {
                        std::swap(T[v][i], T[v].back());
                        break;
                    }
                    assert(T[v].back() == p);
                    T[v].pop_back();
                }
                for (V x : T[v]) {
                    size_[v] += dfs(dfs, x, v, d + 1);
                }
                for (u32 i{1} ; i < T[v].size() ; i++) if (size_[T[v][0]] < size_[T[v][i]]) {
                    std::swap(T[v][0], T[v][i]);
                }
                return size_[v];
            }};

            auto dfs2{[&](auto dfs, V v, V idx, V top) -> V {
                idx_[v] = idx++;
                inv_[idx_[v]] = v;
                top_[v] = top;
                if (T[v].size()) {
                    idx = dfs(dfs, T[v][0], idx, top);
                    for (u32 i{1} ; i < T[v].size() ; i++) {
                        idx = dfs(dfs, T[v][i], idx, T[v][i]);
                    }
                }
                return idx;
            }};

            dfs1(dfs1, root, INVALID, 0u);
            dfs2(dfs2, root, 0u, root);
        }

    inline usize size() const noexcept {
        return n_;
    }

    usize size(V v) const noexcept {
        assert(v < (V)size());
        return size_[v];
    }

    usize depth(V v) const noexcept {
        assert(v < (V)size());
        return dep_[v];
    }

    V parent(V v) const noexcept {
        assert(v < (V)size());
        return par_[v];
    }

    V index(V v) const noexcept {
        assert(v < (V)size());
        return idx_[v];
    }

    V operator[](V v) const noexcept {
        assert(v < (V)size());
        return idx_[v];
    }

    std::vector<std::pair<V, V>> decomp(V s, V t) const {
        assert(s < (V)size());
        assert(t < (V)size());
        std::vector<std::pair<V, V>> res, ser;
        while (top_[s] != top_[t]) {
            if (dep_[top_[s]] >= dep_[top_[t]]) {
                res.emplace_back(s, top_[s]);
                s = top_[s];
                if (par_[s] != INVALID) s = par_[s];
            }
            else {
                ser.emplace_back(top_[t], t);
                t = top_[t];
                if (par_[t] != INVALID) t = par_[t];
            }
        }
        res.emplace_back(s, t);
        std::reverse(ser.begin(), ser.end());
        res.insert(res.end(), ser.begin(), ser.end()); 
        return res;
    }

    std::vector<std::pair<V, V>> operator()(V s, V t) const {
        return decomp(s, t);
    }

    V lca(V u, V v) const {
        assert(u < (V)size());
        assert(v < (V)size());
        while (top_[u] != top_[v]) {
            if (dep_[top_[u]] >= dep_[top_[v]]) {
                u = top_[u];
                if (par_[u] != INVALID) u = par_[u];
            }
            else {
                v = top_[v];
                if (par_[v] != INVALID) v = par_[v];
            }
        }
        return (dep_[u] <= dep_[v] ? u : v);
    }

    // pはvの祖先か？
    bool isAncestor(V v, V p) {
        assert(v < size());
        assert(p < size());
        if (dep_[v] < dep_[p]) return false;
        while (v != INVALID and top_[v] != top_[p]) {
            v = par_[top_[v]];
        }
        return v != INVALID;
    }

    V levelAncestor(V v, usize step) const {
        assert(v < (V)size());
        if (step > dep_[v]) return INVALID;
        while (true) {
            usize dist{dep_[v] - dep_[top_[v]]};
            if (dist >= step) break;
            step -= dist + 1;
            v = par_[top_[v]];
        }
        step = (dep_[v] - dep_[top_[v]]) - step;
        return inv_[idx_[top_[v]] + step];
    }

    V jump(V s, V t, usize step) const {
        assert(s < (V)size());
        assert(t < (V)size());
        V uu{INVALID}, vv{INVALID};
        usize d{};
        for (auto [u, v] : decomp(s, t)) {
            usize dist{std::max(dep_[u], dep_[v]) - std::min(dep_[u], dep_[v])};
            if (dist >= step) {
                uu = u;
                vv = v;
                d = dist;
                break;
            }
            step -= dist + 1;
        }
        if (uu == INVALID) return INVALID;
        if (dep_[uu] <= dep_[vv]) {
            return inv_[idx_[uu] + step];
        }
        else {
            return inv_[idx_[vv] + (d - step)];
        }
    }

    usize distance(V s, V t) const {
        assert(s < (V)size());
        assert(t < (V)size());
        usize res{};
        for (auto [u, v] : decomp(s, t)) {
            if (dep_[u] > dep_[v]) std::swap(u, v);
            res += dep_[v] - dep_[u];
        }
        return res;
    }

private:
    static constexpr V INVALID{static_cast<V>(-1)};
    usize n_{};
    std::vector<V> par_{}, top_{}, idx_{}, inv_{};
    std::vector<usize> size_{}, dep_{};
};

} // namespace zawa
#line 5 "0465.test.cpp"

#line 10 "0465.test.cpp"

#line 1 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/modint.hpp"



#line 5 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/modint.hpp"
#include <numeric>
#include <type_traits>

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

#line 1 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/internal_math.hpp"



#line 5 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/internal_math.hpp"

#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);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#line 1 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/internal_type_traits.hpp"



#line 7 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/internal_type_traits.hpp"

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


#line 14 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/modint.hpp"

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>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

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

    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 += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        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 {
        auto eg = internal::inv_gcd(_v, mod());
        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 internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

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>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


#line 12 "0465.test.cpp"
using mint = atcoder::modint998244353;
using namespace zawa;

int main() {
    SetFastIO();

    int N;
    std::cin >> N;
    std::vector<std::vector<int>> T(N);
    for (int _{} ; _ < N - 1 ; _++) {
        int s, t;
        std::cin >> s >> t;
        s--; t--;
        T[s].push_back(t);
        T[t].push_back(s);
    }
    HeavyLightDecomposition hld(T, 0);
    std::vector<mint> prod(N), invprod(N);
    auto dfs{[&](auto dfs, int v, int p) -> void {
        prod[v] = (p == -1 ? mint::raw(1) : prod[p] * mint{hld.size(p) - hld.size(v)});
        invprod[v] = prod[v].inv();
        for (auto x : T[v]) if (x != p) dfs(dfs, x, v);
    }};
    dfs(dfs, 0, -1);
    int Q;
    std::cin >> Q;
    while (Q--) {
        int u, v;
        std::cin >> u >> v;
        u--; v--;
        if (hld.depth(u) < hld.depth(v)) std::swap(u, v);
        int lca{(int)hld.lca(u, v)};
        assert(u != lca);
        if (v == lca) {
            auto a{hld.levelAncestor(u, hld.depth(u) - hld.depth(v) - 1)};
            assert(a != hld.Invalid());
            mint ans{prod[u] * invprod[a]};
            std::cout << ans.val() << '\n';
        } 
        else {
            auto a{hld.levelAncestor(u, hld.depth(u) - hld.depth(lca) - 1)};
            auto b{hld.levelAncestor(v, hld.depth(v) - hld.depth(lca) - 1)};
            assert(a != hld.Invalid());
            assert(b != hld.Invalid());
            mint ans{1};
            ans *= prod[u] * invprod[a];
            ans *= mint{N - hld.size(a) - hld.size(b)};
            ans *= prod[v] * invprod[b];
            std::cout << ans.val() << '\n';
        }
    }
}
accuracy: 1
time_ms: 60
memory_kb: 26488
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll mod = 998244353;
ll power(ll a,ll b){
  ll res = 1;
  while(b>0){
    if(b%2==0){
      b/=2;
      a*=a;
      a%=mod;
    }else{
      b--;
      res*=a;
      res%=mod;
    }
  }
  return res;
}
struct segtree{
  int n;
  vector<ll> node;
  segtree(int N){
    n = 1;
    while(n<N) n*=2;
    node.resize(2*n-1,1);
  }
  void update(ll a,ll x){
    int i = a+n-1;
    node[i] = x;
    while(i>0){
      i=(i-1)/2;
      node[i] = (node[i*2+1]*node[i*2+2])%mod;
    }
  }
  ll find(ll a,ll b,ll k=0,ll l=0,ll r=-1){
    if(r<0) r = n;
    if(b<=l||r<=a) return 1;
    if(a<=l&&r<=b) return node[k];
    ll vl = find(a,b,k*2+1,l,(l+r)/2);
    ll vr = find(a,b,k*2+2,(l+r)/2,r);
    return (vl*vr)%mod;
  }
};
int main() {
  int N;
  cin >> N;
  vector<vector<int>> G(N);
  for(int i=0;i<N-1;i++){
    int a,b;
    cin >> a >> b;
    a--;
    b--;
    G[a].push_back(b);
    G[b].push_back(a);
  }
  for(int i=0;i<N;i++){
    sort(G[i].begin(),G[i].end());
  }
  vector<ll> A(N,1);
  vector<ll> parent(N);
  vector<ll> depth(N,0);
  auto dfs = [&](auto dfs,int u,int p)->void{
    for(auto v:G[u]){
      if(v==p) continue;
      depth[v] = depth[u]+1;
      dfs(dfs,v,u);
      A[u] += A[v];
      parent[v] = u;
    }
  };
  dfs(dfs,0,-1);
  parent[0] = -1;
  vector<vector<ll>> rp(20,vector<ll>(N,0));
  rp[0] = parent;
  for(int i=0;i<19;i++){
    for(int j=0;j<N;j++){
      if(rp[i][j]==-1) rp[i+1][j] = -1;
      else rp[i+1][j] = rp[i][rp[i][j]]; 
    }
  }
  vector<vector<ll>> chsum(N);
  for(int i=0;i<N;i++){
    for(auto j:G[i]) {
        chsum[i].push_back(A[j]);
    }
  }
  for(int i=0;i<N;i++){
    for(int j=0;j<chsum[i].size()-1;j++){
      chsum[i][j+1] += chsum[i][j];
      chsum[i][j+1]%=mod;
    }
  }
  vector<ll> dp(N);
  dp[0] = 1;
  auto dfs1 = [&](auto dfs1,int u,int p)->void{
    for(auto v:G[u]){
      if(v==p) continue;
      dp[v] = dp[u]*(A[u]-A[v]);
      dp[v] %= mod;
      dfs1(dfs1,v,u);
    }
  };
  dfs1(dfs1,0,-1);
  auto calcLCA = [&](ll a,ll b)->pair<ll,ll>{
    if(depth[a]>depth[b]) swap(a,b);
    int pa = -1;
    int pb = -1;
    for(int w=19;w>=0;w--){
      const int o = rp[w][b];
      if(o==-1) continue;
      if(depth[o]>depth[a]) {
        b = o;
      }
    }
    pb = b;
    if(depth[a]!=depth[b])b = parent[b];
    if(a==b) return pair(pa,pb);
    for(int w=19;w>=0;w--){
      int na = rp[w][a], nb = rp[w][b];
      if(na!=nb){
        a = na;
        b = nb;
      }
    }
    return pair(a,b);
  };
  int Q;
  cin >> Q;
  for(int i=0;i<Q;i++){
    int u,v;
    cin >> u >> v;
    u--;
    v--;
    if(depth[u]>depth[v]) swap(u,v);
    pair<ll,ll> p = calcLCA(u,v);
    ll ans = 1;
    ll sum = 0;
    if(p.first==-1){
      ans *= (dp[v]*power(dp[parent[p.second]],mod-2))%mod;
      ans %= mod;
      sum += A[parent[p.second]]-A[p.second];
      ans *= power(sum,mod-2);
      ans %= mod;
    }else{
        sum++;
      if(parent[p.second]!=0){
        sum += A[0]-A[parent[p.second]];
      }
      ll a = lower_bound(G[parent[p.first]].begin(),G[parent[p.first]].end(),p.first)-G[parent[p.first]].begin();
      ll b = lower_bound(G[parent[p.first]].begin(),G[parent[p.first]].end(),p.second)-G[parent[p.first]].begin();
      if(a>b) swap(a,b);
      if(a>0){
        sum += chsum[parent[p.first]][a-1];
      }
      if(b-a>1){
        sum += chsum[parent[p.first]][b-1]-chsum[parent[p.first]][a];
      }
      sum += chsum[parent[p.first]][chsum[parent[p.first]].size()-1]-chsum[parent[p.first]][b];
      if(parent[parent[p.first]]!=-1) sum -= A[parent[parent[p.first]]];
      sum %= mod;
      ans *= (dp[u]*power(dp[p.first],mod-2))%mod;
      ans %= mod;
      ans *= (dp[v]*power(dp[p.second],mod-2))%mod;
      ans %= mod;
      if(sum!=0) ans *= sum;
      ans %= mod;
    }
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 340
memory_kb: 43584
final_rank: 18

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


#include <utility>

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 < 2^31`
    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 int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @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


#include <cassert>
#include <numeric>
#include <type_traits>

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

#include <cassert>
#include <numeric>
#include <type_traits>

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

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());
    }
    static_modint(bool 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>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

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

    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 += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        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 {
        auto eg = internal::inv_gcd(_v, mod());
        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 internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

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>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

using namespace std;
using mint = atcoder::modint998244353;

int main()
{
        long long n;
        cin >> n;
        vector<vector<long long>> g(n,vector<long long>());
        for(long long i = 0ll;i < n - 1ll;i++){
                long long u,v;
                cin >> u >> v;
                u--;v--;
                g[u].push_back(v);
                g[v].push_back(u);
        }
        vector<vector<long long>> r(n,vector<long long>(20ll));
        vector<mint> cou(n,0ll),c(n);
        vector<long long> d(n,-1ll);
        {
                d[0ll] = 0ll;
                queue<long long> q;
                q.push(0ll);
                while(!q.empty()){
                        long long it = q.front();
                        q.pop();
                        for(long long i : g[it]){
                                if(d[i] != -1ll) continue;
                                d[i] = d[it] + 1ll;
                                q.push(i);
                        }
                }
                for(long long i = 0ll;i < n;i++){
                        r[i][0ll] = i;
                        for(long long j : g[i]){
                                if(d[j] < d[i]){
                                        r[i][0ll] = j;
                                }
                        }
                }
                for(long long i = 1ll;i < 20ll;i++){
                        for(long long j = 0ll;j < n;j++){
                                r[j][i] = r[r[j][i - 1ll]][i - 1ll];
                        }
                }
                auto cal = [&](auto cal,long long now) -> mint {
                        cou[now]++;
                        for(long long i : g[now]){
                                if(d[i] > d[now]){
                                        cou[now] += cal(cal,i);
                                }
                        }
                        return cou[now];
                };
                cal(cal,0ll);
        }
        {
                queue<long long> q;
                for(long long i : g[0ll]){
                        c[i] = 1ll;
                        for(long long j : g[i]){
                                if(j == 0ll) continue;
                                q.push(j);
                        }
                }
                while(!q.empty()){
                        long long it = q.front();
                        q.pop();
                        c[it] = c[r[it][0ll]] * (cou[r[it][0ll]] - cou[it]);
                        for(long long i : g[it]){
                                if(d[i] > d[it]){
                                        q.push(i);
                                }
                        }
                }
        }
        auto root = [&](long long x,long long y) -> long long {
                if(y < 0ll) return x;
                long long res = x;
                for(long long i = 0ll;i < 20ll;i++){
                        if(y & (1ll << i)){
                                res = r[res][i];
                        }
                }
                return res;
        };
        auto lca = [&](long long a,long long b) -> long long {
                if(d[a] > d[b]){
                        a = root(a,d[a] - d[b]);
                }
                if(d[a] < d[b]){
                        b = root(b,d[b] - d[a]);
                }
                long long low = 0ll,high = n;
                while(low < high){
                        long long mid = (low + high) / 2ll;
                        if(root(a,mid) == root(b,mid)){
                                high = mid;
                        }else{
                                low = mid + 1ll;
                        }
                }
                return low;
        };
        long long Q;
        cin >> Q;
        for(long long i = 0ll;i < Q;i++){
                long long u,v;
                cin >> u >> v;
                u--;v--;
                pair<long long,long long> dis(lca(u,v),lca(u,v));
                if(d[u] > d[v]){
                        dis.first += d[u] - d[v];
                }
                if(d[u] < d[v]){
                        dis.second += d[v] - d[u];
                }
                pair<long long,long long> p = {root(u,dis.first - 1ll),root(v,dis.second - 1ll)};
                long long it = root(u,dis.first);
                mint ans = 0ll;
                if(it == u){
                        ans = c[v] / c[p.second];
                }else if(it == v){
                        ans = c[u] / c[p.first];
                }else if(it == 0ll){
                        ans = c[u] * c[v];
                        ans *= n - cou[p.first] - cou[p.second];
                }else{
                        ans = c[u] / c[p.first];
                        ans *= c[v] / c[p.second];
                        ans *= n - cou[p.first] - cou[p.second];
                }
                cout << ans.val() << endl;
        }
}
accuracy: 1
time_ms: 370
memory_kb: 37296
final_rank: 16

code_snippet: #line 1 "0465.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/problems/0465"

#line 2 "/home/zawatin/compro/cp-documentation/Src/Template/IOSetting.hpp"

#line 2 "/home/zawatin/compro/cp-documentation/Src/Template/TypeAlias.hpp"

#include <cstdint>
#include <cstddef>

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
#line 4 "/home/zawatin/compro/cp-documentation/Src/Template/IOSetting.hpp"

#include <iostream>
#include <iomanip>

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
#line 2 "/home/zawatin/compro/cp-documentation/Src/Graph/Tree/Tree.hpp"

#line 4 "/home/zawatin/compro/cp-documentation/Src/Graph/Tree/Tree.hpp"

#include <cassert>
#include <vector>

namespace zawa {

using Tree = std::vector<std::vector<u32>>;

void AddEdge(Tree& T, u32 u, u32 v) {
    assert(u < T.size());
    assert(v < T.size());
    T[u].emplace_back(v);
    T[v].emplace_back(u);
}

void AddDirectedEdge(Tree& T, u32 from, u32 to) {
    assert(from < T.size());
    assert(to < T.size());
    T[from].emplace_back(to);
}

} // namespace zawa
#line 2 "/home/zawatin/compro/cp-documentation/Src/Graph/Tree/HeavyLightDecomposition.hpp"

#line 5 "/home/zawatin/compro/cp-documentation/Src/Graph/Tree/HeavyLightDecomposition.hpp"

#include <algorithm>
#line 8 "/home/zawatin/compro/cp-documentation/Src/Graph/Tree/HeavyLightDecomposition.hpp"
#include <cmath>
#include <limits>
#include <utility>
#line 12 "/home/zawatin/compro/cp-documentation/Src/Graph/Tree/HeavyLightDecomposition.hpp"

namespace zawa {

class HeavyLightDecomposition {
public:
    using Vertex = u32;

    static constexpr Vertex Invalid() noexcept {
        return INVALID;
    }

    HeavyLightDecomposition() = default;

    HeavyLightDecomposition(Tree T, Vertex root = 0u) 
        : n_{T.size()}, par_(n_), top_(n_), idx_(n_), 
        inv_(n_), size_(n_, usize{1}), dep_(n_) {

            auto dfs1{[&](auto dfs, Vertex v, Vertex p, usize d) -> usize {
                par_[v] = p;
                dep_[v] = d;
                if (p != INVALID) {
                    for (u32 i{} ; i + 1 < T[v].size() ; i++) if (T[v][i] == p) {
                        std::swap(T[v][i], T[v].back());
                        break;
                    }
                    assert(T[v].back() == p);
                    T[v].pop_back();
                }
                for (Vertex x : T[v]) {
                    size_[v] += dfs(dfs, x, v, d + 1);
                }
                for (u32 i{1} ; i < T[v].size() ; i++) if (size_[T[v][0]] < size_[T[v][i]]) {
                    std::swap(T[v][0], T[v][i]);
                }
                return size_[v];
            }};

            auto dfs2{[&](auto dfs, Vertex v, Vertex idx, Vertex top) -> Vertex {
                idx_[v] = idx++;
                inv_[idx_[v]] = v;
                top_[v] = top;
                if (T[v].size()) {
                    idx = dfs(dfs, T[v][0], idx, top);
                    for (u32 i{1} ; i < T[v].size() ; i++) {
                        idx = dfs(dfs, T[v][i], idx, T[v][i]);
                    }
                }
                return idx;
            }};

            dfs1(dfs1, root, INVALID, 0u);
            dfs2(dfs2, root, 0u, root);
        }

    inline usize size() const noexcept {
        return n_;
    }

    usize size(Vertex v) const noexcept {
        assert(v < size());
        return size_[v];
    }

    usize depth(Vertex v) const noexcept {
        assert(v < size());
        return dep_[v];
    }

    Vertex parent(Vertex v) const noexcept {
        assert(v < size());
        return par_[v];
    }

    Vertex index(Vertex v) const noexcept {
        assert(v < size());
        return idx_[v];
    }

    Vertex operator[](Vertex v) const noexcept {
        assert(v < size());
        return idx_[v];
    }


    std::vector<std::pair<Vertex, Vertex>> decomp(Vertex s, Vertex t) const {
        assert(s < size());
        assert(t < size());
        std::vector<std::pair<Vertex, Vertex>> res, ser;
        while (top_[s] != top_[t]) {
            if (dep_[top_[s]] >= dep_[top_[t]]) {
                res.emplace_back(s, top_[s]);
                s = top_[s];
                if (par_[s] != INVALID) s = par_[s];
            }
            else {
                ser.emplace_back(top_[t], t);
                t = top_[t];
                if (par_[t] != INVALID) t = par_[t];
            }
        }
        res.emplace_back(s, t);
        std::reverse(ser.begin(), ser.end());
        res.insert(res.end(), ser.begin(), ser.end()); 
        return res;
    }

    std::vector<std::pair<Vertex, Vertex>> operator()(Vertex s, Vertex t) const {
        return decomp(s, t);
    }

    Vertex lca(u32 u, u32 v) const {
        assert(u < size());
        assert(v < size());
        while (top_[u] != top_[v]) {
            if (dep_[top_[u]] >= dep_[top_[v]]) {
                u = top_[u];
                if (par_[u] != INVALID) u = par_[u];
            }
            else {
                v = top_[v];
                if (par_[v] != INVALID) v = par_[v];
            }
        }
        return (dep_[u] <= dep_[v] ? u : v);
    }

    // pはvの祖先か？
    bool isAncestor(Vertex v, Vertex p) {
        assert(v < size());
        assert(p < size());
        if (dep_[v] < dep_[p]) return false;
        while (v != INVALID and top_[v] != top_[p]) {
            v = par_[top_[v]];
        }
        return v != INVALID;
    }

    Vertex levelAncestor(Vertex v, usize step) const {
        assert(v < size());
        if (step > dep_[v]) return INVALID;
        while (true) {
            usize dist{dep_[v] - dep_[top_[v]]};
            if (dist >= step) break;
            step -= dist + 1;
            v = par_[top_[v]];
        }
        step = (dep_[v] - dep_[top_[v]]) - step;
        return inv_[idx_[top_[v]] + step];
    }

    Vertex jump(Vertex s, Vertex t, usize step) const {
        assert(s < size());
        assert(t < size());
        Vertex uu{INVALID}, vv{INVALID};
        usize d{};
        for (auto [u, v] : decomp(s, t)) {
            usize dist{std::max(dep_[u], dep_[v]) - std::min(dep_[u], dep_[v])};
            if (dist >= step) {
                uu = u;
                vv = v;
                d = dist;
                break;
            }
            step -= dist + 1;
        }
        if (uu == INVALID) return INVALID;
        if (dep_[uu] <= dep_[vv]) {
            return inv_[idx_[uu] + step];
        }
        else {
            return inv_[idx_[vv] + (d - step)];
        }
    }

    usize distance(Vertex s, Vertex t) const {
        assert(s < size());
        assert(t < size());
        usize res{};
        for (auto [u, v] : decomp(s, t)) {
            if (dep_[u] > dep_[v]) std::swap(u, v);
            res += dep_[v] - dep_[u];
        }
        return res;
    }

private:
    static constexpr Vertex INVALID{static_cast<Vertex>(-1)};
    usize n_{};
    std::vector<Vertex> par_{}, top_{}, idx_{}, inv_{};
    std::vector<usize> size_{}, dep_{};
};

} // namespace zawa
#line 6 "0465.test.cpp"

#line 11 "0465.test.cpp"

#line 1 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/modint.hpp"



#line 5 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/modint.hpp"
#include <numeric>
#include <type_traits>

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

#line 1 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/internal_math.hpp"



#line 5 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/internal_math.hpp"

#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);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#line 1 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/internal_type_traits.hpp"



#line 7 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/internal_type_traits.hpp"

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


#line 14 "/home/zawatin/compro/cp-documentation/ac-library/atcoder/modint.hpp"

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>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

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

    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 += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        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 {
        auto eg = internal::inv_gcd(_v, mod());
        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 internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

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>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


#line 13 "0465.test.cpp"
using mint = atcoder::modint998244353;
using namespace zawa;

int main() {
    SetFastIO();

    int N;
    std::cin >> N;
    Tree T(N);
    for (int _{} ; _ < N - 1 ; _++) {
        int s, t;
        std::cin >> s >> t;
        s--; t--;
        AddEdge(T, s, t);
    }
    HeavyLightDecomposition hld(T, 0);
    std::vector<mint> prod(N), invprod(N);
    auto dfs{[&](auto dfs, int v, int p) -> void {
        prod[v] = (p == -1 ? mint::raw(1) : prod[p] * mint{hld.size(p) - hld.size(v)});
        invprod[v] = prod[v].inv();
        for (auto x : T[v]) if (x != p) dfs(dfs, x, v);
    }};
    dfs(dfs, 0, -1);
    int Q;
    std::cin >> Q;
    while (Q--) {
        int u, v;
        std::cin >> u >> v;
        u--; v--;
        if (hld.depth(u) < hld.depth(v)) std::swap(u, v);
        int lca{(int)hld.lca(u, v)};
        assert(u != lca);
        if (v == lca) {
            auto a{hld.levelAncestor(u, hld.depth(u) - hld.depth(v) - 1)};
            assert(a != hld.Invalid());
            mint ans{prod[u] * invprod[a]};
            std::cout << ans.val() << '\n';
        } 
        else {
            auto a{hld.levelAncestor(u, hld.depth(u) - hld.depth(lca) - 1)};
            auto b{hld.levelAncestor(v, hld.depth(v) - hld.depth(lca) - 1)};
            assert(a != hld.Invalid());
            assert(b != hld.Invalid());
            mint ans{1};
            ans *= prod[u] * invprod[a];
            ans *= mint{N - hld.size(a) - hld.size(b)};
            ans *= prod[v] * invprod[b];
            std::cout << ans.val() << '\n';
        }
    }
}
accuracy: 1
time_ms: 70
memory_kb: 26368
final_rank: 6

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



#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);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // 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>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

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

    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 += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        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 {
        auto eg = internal::inv_gcd(_v, mod());
        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 internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

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>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


using mint = atcoder::modint998244353;

std::vector<int> g[100100];
int par[100100], sz[100100], dep[100100];
void dfs_par(int v, int p) {
    par[v] = p;
    for (int i{} ; i + 1 < (int)g[v].size() ; i++) {
        if (g[v][i] == p) std::swap(g[v][i], g[v].back());
    }
    if (g[v].back() == p) g[v].pop_back();
    for (auto x : g[v]) dfs_par(x, v);
}
int dfs_sz(int v) {
    sz[v] = 1;
    for (auto x : g[v]) sz[v] += dfs_sz(x);
    return sz[v];
}
void dfs_dep(int v, int d) {
    dep[v] = d;
    for (auto x : g[v]) dfs_dep(x, d + 1);
}
void dfs_hld(int v) {
    for (int i{1} ; i < (int)g[v].size() ; i++) {
        if (sz[g[v][0]] < sz[g[v][i]]) std::swap(g[v][0], g[v][i]);
    }
    for (auto x : g[v]) dfs_hld(x);
}
int idx[100100], top[100100];
int dfs_decomp(int v, int tp, int id) {
    idx[v] = id++;
    top[v] = tp;
    if (g[v].size()) id = dfs_decomp(g[v][0], tp, id);
    for (int i{1} ; i < (int)g[v].size() ; i++) {
        id = dfs_decomp(g[v][i], g[v][i], id);
    }
    return id;
}
mint travel(int v, int i) {
    assert(i < (int)g[v].size());
    return mint::raw(sz[v] - sz[g[v][i]]);
}
mint A[100100], invA[100100], mult[100100], invmult[100100];
std::map<std::pair<int, int>, int> edge;
int main() {
    int N;
    std::cin >> N;
    for (int _{} ; _ < N - 1 ; _++) {
        int s, t;
        std::cin >> s >> t;
        s--; t--;
        g[s].push_back(t);
        g[t].push_back(s);
    }
    dfs_par(0, -1);
    dfs_sz(0);
    dfs_dep(0, 0);
    dfs_hld(0);
    dfs_decomp(0, 0, 0);
    mult[0] = invmult[0] = mint::raw(1);
    for (int v{} ; v < N ; v++) {
        A[idx[v]] = (sz[v] == 1 ? mint::raw(1) : travel(v, 0));
        invA[idx[v]] = A[idx[v]].inv();
    }
    for (int v{} ; v < N ; v++) {
        mult[v + 1] = mult[v] * A[v];
        invmult[v + 1] = mult[v + 1].inv();
    }
    for (int v{} ; v < N ; v++) {
        for (int i{} ; i < (int)g[v].size() ; i++) {
            edge[std::make_pair(v, g[v][i])] = i;
        }
    }
    int Q;
    std::cin >> Q;
    while (Q--) {
        int u, v;
        std::cin >> u >> v;
        u--; v--;
        int pu{-1}, pv{-1};
        mint ans{1};
        while (top[u] != top[v]) {
            if (dep[top[u]] >= dep[top[v]]) {
                // std::cout << u + 1 << " -> " << top[u] + 1 << std::endl;
                int L{idx[top[u]]}, R{idx[u]};
                assert(L <= R);
                mint cur{mult[R] * invmult[L]};
                if (pu != -1) {
                    std::pair<int, int> search{u, pu};
                    auto it{edge.find(search)};
                    assert(it != edge.end());
                    cur *= travel(u, it->second);
                }
                // std::cout << cur.val() << std::endl;
                ans *= cur;
                u = top[u];
                pu = u;
                if (par[u] != -1) u = par[u];
            }
            else {
                int L{idx[top[v]]}, R{idx[v]};
                // std::cout << v + 1 << " -> " << top[v] + 1 << std::endl;
                assert(L <= R);
                mint cur{mult[R] * invmult[L]};
                if (pv != -1) {
                    std::pair<int, int> search{v, pv};
                    auto it{edge.find(search)};
                    assert(it != edge.end());
                    cur *= travel(v, it->second);
                }
                // std::cout << cur.val() << std::endl;
                ans *= cur;
                v = top[v];
                pv = v;
                if (par[v] != -1) v = par[v];
            }
        }
        if (u != v) {
            assert(dep[u] != dep[v]);
            if (dep[u] > dep[v]) {
                std::swap(u, v);
                std::swap(pu, pv);
            }
            // std::cout << u + 1 << " -> " << v + 1 << std::endl;
            int L{idx[u]}, R{idx[v]};
            assert(L < R);
            mint cur{mult[R] * invmult[L]};
            if (pv != -1 and pv != v) {
                std::pair<int, int> search{v, pv};
                auto it{edge.find(search)};
                assert(it != edge.end());
                cur *= travel(v, it->second);
            }

            cur *= invA[idx[u]];
            if (pu != -1) {
                int num{sz[u]};
                if (pu != u) {
                    auto it{edge.find(std::make_pair(u, pu))};
                    assert(it != edge.end());
                    assert(it->second != 0);
                    num -= sz[g[u][it->second]];
                }
                if (sz[u] != 1) {
                    num -= sz[g[u][0]];
                }
                if (pu != -1) {
                    num += N - sz[u];
                }
                cur *= num;
            }

            // std::cout << cur.val() << std::endl;
            ans *= cur;
        }
        else if (pu != -1 and pv != -1) {
            // std::cout << "only top " << u + 1 << std::endl;
            // std::cout << pu + 1 << ' ' << pv + 1 << std::endl;
            mint cur{N};
            cur -= sz[u == pu ? 0 : g[u][edge.find(std::make_pair(u, pu))->second]];
            cur -= sz[v == pv ? 0 : g[u][edge.find(std::make_pair(v, pv))->second]];
            // std::cout << cur.val() << std::endl;
            ans *= cur;
        }
        std::cout << ans.val() << '\n';
    }
}
accuracy: 1
time_ms: 360
memory_kb: 21660
final_rank: 12

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

int main() {
  int N;
  cin >> N;
  vector<vector<int>> G(N);
  for( int i = 0; i < N-1; i++ ) {
    int s, t;
    cin >> s >> t;
    s--, t--;
    G[s].push_back(t);
    G[t].push_back(s);
  }
  vector<int> d(N, 1), s(N, 1), p(N, -1);
  auto dfs = [&](auto dfs, int cur, int pre) -> void {
    for( const int &nxt : G[cur] ) {
      if( nxt == pre ) continue;
      p[nxt] = cur;
      d[nxt] = d[cur]+1;
      dfs(dfs, nxt, cur);
      s[cur] += s[nxt];
    }
  };
  dfs(dfs, 0, -1);
  constexpr int lg = 18;
  constexpr long long MOD = 998244353;
  vector<vector<int>> dest(lg, vector<int>(N, -1));
  vector<vector<long long>> prod(lg, vector<long long>(N, 0));
  for( int i = 0; i < N; i++ ) {
    dest[0][i] = p[i];
    if( dest[0][i] == -1 ) continue;
    prod[0][i] = s[p[i]]-s[i];
  }
  for( int k = 1; k < lg; k++ ) {
    for( int i = 0; i < N; i++ ) {
      if( dest[k-1][i] == -1 ) continue;
      dest[k][i] = dest[k-1][dest[k-1][i]];
      prod[k][i] = prod[k-1][i]*prod[k-1][dest[k-1][i]]%MOD;
    }
  }
  int Q;
  cin >> Q;
  for( int q = 0; q < Q; q++ ) {
    int u, v;
    cin >> u >> v;
    u--, v--;
    if( d[u] < d[v] ) swap(u, v);
    int diff = abs(d[u]-d[v]);
    long long ret = 1;
    for( int k = lg-1; k >= 0; k-- ) {
      if( diff > 0 && ((diff-1)>>k)%2 == 1 ) {
        ret *= prod[k][u];
        ret %= MOD;
        u = dest[k][u];
      }
    }
    if( dest[0][u] == v ) {
      cout << ret << endl;
      continue;
    }else if( diff > 0 ) {
      ret *= prod[0][u];
      ret %= MOD;
      u = dest[0][u];
    }
    for( int k = lg-1; k >= 0; k-- ) {
      if( dest[k][u] != dest[k][v] ) {
        ret *= prod[k][u];
        ret %= MOD;
        u = dest[k][u];
        ret *= prod[k][v];
        ret %= MOD;
        v = dest[k][v];
      }
    }
    ret *= N-(s[u]+s[v]);
    ret %= MOD;
    cout << ret << endl;
  }
}
accuracy: 1
time_ms: 180
memory_kb: 40900
final_rank: 14

code_snippet: // time complexity: O(N + Q * (log N + log MOD))

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

const int MOD = 998244353;

class modint {
private:
	int x;
public:
	modint() : x(0) {}
	modint(long long n) : x(n >= 0 ? n % MOD : (MOD - (-n) % MOD) % MOD) {}
	int get() const { return x; }
	modint operator-() const { return modint(x != 0 ? MOD - x : 0); }
	modint operator+=(const modint& m) { x = (x + m.x) % MOD; return *this; }
	modint operator-=(const modint& m) { x = (x - m.x + MOD) % MOD; return *this; }
	modint operator*=(const modint& m) { x = 1LL * x * m.x % MOD; return *this; }
	modint operator+(const modint& m) const { return modint(*this) += m; }
	modint operator-(const modint& m) const { return modint(*this) -= m; }
	modint operator*(const modint& m) const { return modint(*this) *= m; }
	modint pow(long long b) const {
		modint res(1), a(*this);
		while (b >= 1) {
			if (b % 2 == 1) {
				res *= a;
			}
			a *= a;
			b /= 2;
		}
		return res;
	}
	modint inv() const {
		return pow(MOD - 2);
	}
};

int main() {
	// step #1. input & make graph
	cin.tie(0);
	ios::sync_with_stdio(false);
	int N;
	cin >> N;
	vector<vector<int> > G(N);
	for (int i = 0; i < N - 1; i++) {
		int a, b;
		cin >> a >> b;
		G[a - 1].push_back(b - 1);
		G[b - 1].push_back(a - 1);
	}

	// step #2. ordering
	vector<int> subsize(N);
	vector<int> par(N, -1);
	vector<vector<int> > child(N);
	auto ordering = [&](auto& self, int pos) -> void {
		subsize[pos] = 1;
		for (int i : G[pos]) {
			if (i != par[pos]) {
				par[i] = pos;
				child[pos].push_back(i);
				self(self, i);
				subsize[pos] += subsize[i];
			}
		}
		for (int& v : child[pos]) {
			if (subsize[v] > subsize[child[pos][0]]) {
				swap(v, child[pos][0]);
			}
		}
	};
	ordering(ordering, 0);

	// step #3. calculate multiples
	vector<modint> mult(N);
	for (int i = 0; i < N; i++) {
		if (i != 0 && !child[i].empty()) {
			mult[i] = subsize[i] - subsize[child[i][0]];
		}
		else {
			mult[i] = 1;
		}
	}

	// step #4. build tree
	int counter = 0;
	vector<int> ordinv(N);
	vector<int> ord(N);
	vector<int> head(N);
	auto build_tree = [&](auto& self, int pos) -> void {
		ord[pos] = counter;
		ordinv[counter] = pos;
		counter += 1;
		for (int i : child[pos]) {
			head[i] = (i == child[pos][0] ? head[pos] : i);
			if (i == child[pos][0]) {
				mult[i] *= mult[pos];
			}
			self(self, i);
		}
	};
	build_tree(build_tree, 0);

	// step #5. lca
	auto lcainfo = [&](int va, int vb) -> array<int, 3> {
		array<int, 3> res = { -1, -1, -1 };
		while (head[va] != head[vb]) {
			if (ord[va] < ord[vb]) {
				res[2] = head[vb];
				vb = par[head[vb]];
			}
			else {
				res[1] = head[va];
				va = par[head[va]];
			}
		}
		if (ord[va] < ord[vb]) {
			res[2] = ordinv[ord[va] + 1];
		}
		if (ord[va] > ord[vb]) {
			res[1] = ordinv[ord[vb] + 1];
		}
		res[0] = (ord[va] < ord[vb] ? va : vb);
		return res;
	};

	// step #6. heavy-light decomposition
	auto query = [&](int pos, int tar) -> modint {
		modint ans = 1;
		int pre = pos;
		pos = par[pos];
		while (head[pos] != head[tar]) {
			ans *= subsize[pos] - subsize[pre];
			ans *= (pos != head[pos] ? mult[par[pos]] : modint(1));
			pre = head[pos];
			pos = par[pre];
		}
		ans *= subsize[pos] - subsize[pre];
		if (pos != tar) {
			ans *= mult[par[pos]] * (tar != head[tar] ? mult[par[tar]].inv() : modint(1));
		}
		return ans;
	};

	// step #7. process queries
	int Q;
	cin >> Q;
	for (int id = 1; id <= Q; id++) {
		int s, t;
		cin >> s >> t;
		s -= 1;
		t -= 1;
		array<int, 3> v = lcainfo(s, t);
		modint ans = 1;
		if (v[1] != -1 && v[2] != -1) {
			ans *= N - (subsize[v[1]] + subsize[v[2]]);
		}
		if (v[1] != -1 && s != v[1]) {
			ans *= query(s, v[1]);
		}
		if (v[2] != -1 && t != v[2]) {
			ans *= query(t, v[2]);
		}
		cout << ans.get() << '\n';
	}

	return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 30280
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
template <class T, class U>
inline bool chmax(T& a, U b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <class T, class U>
inline bool chmin(T& a, U b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
constexpr int INF = 1000000000;
constexpr int64_t llINF = 3000000000000000000;
constexpr double eps = 1e-10;
const double pi = acos(-1);
pair<vector<int>, vector<int>> calc_factor(int n) {
    vector<int> least_factor(n + 1, 0), prime_list;
    for (int i = 2; i <= n; i++) {
        if (least_factor[i] == 0) {
            least_factor[i] = i;
            prime_list.push_back(i);
        }
        for (int j = 0; j < (int)prime_list.size() && i * prime_list[j] <= n; j++) {
            least_factor[i * prime_list[j]] = prime_list[j];
            if (prime_list[j] == least_factor[i]) break;
        }
    }
    return make_pair(least_factor, prime_list);
}
ll extgcd(ll a, ll b, ll& x, ll& y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll d = extgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
ll modpow(ll a, ll b, ll m) {
    ll res = 1;
    while (b) {
        if (b & 1) {
            res *= a;
            res %= m;
        }
        a *= a;
        a %= m;
        b >>= 1;
    }
    return res;
}
template <int modulo>
struct modint {
    int x;
    modint() : x(0) {}
    modint(int64_t y) : x(y >= 0 ? y % modulo : (modulo - (-y) % modulo) % modulo) {}
    modint& operator+=(const modint& p) {
        if ((x += p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint& operator-=(const modint& p) {
        if ((x += modulo - p.x) >= modulo) x -= modulo;
        return *this;
    }
    modint& operator*=(const modint& p) {
        x = (int)(1LL * x * p.x % modulo);
        return *this;
    }
    modint& operator/=(const modint& p) {
        *this *= p.inv();
        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 inv() const {
        int a = x, b = modulo, 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<modulo>(t);
        return (is);
    }
    int val() const { return x; }
    static constexpr int mod() { return modulo; }
    static constexpr int half() { return (modulo + 1) >> 1; }
};
template <typename T>
struct Binomial {
    vector<T> inv, fact, factinv;
    Binomial(int n) {
        assert(n > 0);
        inv.resize(n + 1);
        fact.resize(n + 1);
        factinv.resize(n + 1);
        inv[0] = fact[0] = factinv[0] = 1;
        for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i;
        factinv[n] = fact[n].inv();
        inv[n] = fact[n - 1] * factinv[n];
        for (int i = n - 1; i >= 1; i--) {
            factinv[i] = factinv[i + 1] * (i + 1);
            inv[i] = fact[i - 1] * factinv[i];
        }
    }
    T C(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r] * factinv[r];
    }
    T P(int n, int r) {
        if (n < 0 || n < r || r < 0) return 0;
        return fact[n] * factinv[n - r];
    }
    T H(int n, int r) {
        if (n == 0 && r == 0) return 1;
        if (n < 0 || r < 0) return 0;
        return r == 0 ? 1 : C(n + r - 1, r);
    }
};
template <class S, S (*op)(S, S), S (*e)()>
struct segtree {
    int siz = 1;
    vector<S> dat;
    segtree(int n) : segtree(vector<S>(n, e())) {}
    segtree(const vector<S>& a) {
        while (siz < a.size()) siz <<= 1;
        dat = vector<S>(siz << 1, e());
        for (int i = 0; i < a.size(); i++) dat[siz + i] = a[i];
        for (int i = siz - 1; i >= 1; i--) dat[i] = op(dat[2 * i], dat[2 * i + 1]);
    }
    void set(int p, S x) {
        p += siz;
        dat[p] = x;
        while (p > 0) {
            p >>= 1;
            dat[p] = op(dat[2 * p], dat[2 * p + 1]);
        }
    }
    void add(int p, S x) { set(p, get(p) + x); }
    S get(int p) { return dat[p + siz]; }
    S prod(int l, int r) {
        S vl = e(), vr = e();
        l += siz, r += siz;
        while (l < r) {
            if (l & 1) vl = op(vl, dat[l++]);
            if (r & 1) vr = op(dat[--r], vr);
            l >>= 1, r >>= 1;
        }
        return op(vl, vr);
    }
    S all_prod() { return dat[1]; }
};

template <class T>
struct BIT {
    // 1-indexed
    int n, beki = 1;
    vector<T> bit;
    BIT(int x) {
        bit.resize(x + 1, 0);
        n = x;
        while (beki * 2 <= n) beki *= 2;
    }
    T sum(int i) {
        T res = 0;
        while (i > 0) {
            res += bit[i];
            i -= i & -i;
        }
        return res;
    }
    T sum(int l, int r) {
        //[l,r]
        return sum(r) - (l == 0 ? 0 : sum(l - 1));
    }
    void add(int i, T x) {
        while (i <= n) {
            bit[i] += x;
            i += i & -i;
        }
    }
    int lowerbound(T w) {
        if (w <= 0) return 0;
        int x = 0;
        for (int k = beki; k > 0; k >>= 1) {
            if (x + k <= n && bit[x + k] < w) {
                w -= bit[x + k];
                x += k;
            }
        }
        return x + 1;
    }
};
using mint = modint<998244353>;
template <class T, T (*op)(T, T), T (*e)()>
struct sparsetable {
    vector<vector<T>> table;
    vector<int> logtable;
    sparsetable(vector<T> v) {
        int len = 0;
        while ((1 << len) <= v.size()) len++;
        table.assign(len, vector<T>(1 << len));
        for (int i = 0; i < (int)v.size(); i++) table[0][i] = v[i];
        for (int i = 1; i < len; i++) {
            for (int j = 0; j + (1 << i) <= (1 << len); j++) {
                table[i][j] = op(table[i - 1][j], table[i - 1][j + (1 << (i - 1))]);
            }
        }
        logtable.resize(v.size() + 1);
        for (int i = 2; i < logtable.size(); i++) {
            logtable[i] = logtable[(i >> 1)] + 1;
        }
    }
    T query(int l, int r) {
        assert(l <= r);
        if (l == r) return e();
        int len = logtable[r - l];
        return op(table[len][l], table[len][r - (1 << len)]);
    }
};

struct lca_tree {
    int n, size;
    vector<vector<int>> g, par;
    vector<int> depth;
    lca_tree(vector<vector<int>> g_, int root = 0)
        : n((int)g_.size()), size(log2(n) + 2), g(g_), par(size, vector<int>(n, -1)), depth(vector<int>(n, n)) {
        queue<int> que;
        depth[root] = 0;
        que.push(root);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            for (int i : g[p]) {
                if (depth[i] > depth[p] + 1) {
                    depth[i] = depth[p] + 1;
                    par[0][i] = p;
                    que.push(i);
                }
            }
        }
        for (int k = 0; k < size - 1; k++) {
            for (int i = 0; i < n; i++) {
                if (par[k][i] == -1)
                    par[k + 1][i] = -1;
                else
                    par[k + 1][i] = par[k][par[k][i]];
            }
        }
    }
    int query(int u, int v) {
        if (depth[u] > depth[v]) swap(u, v);
        for (int k = size - 1; k >= 0; k--) {
            if (((depth[v] - depth[u]) >> k) & 1) v = par[k][v];
            if (u == v) return u;
        }
        for (int k = size - 1; k >= 0; k--) {
            if (par[k][u] != par[k][v]) {
                u = par[k][u];
                v = par[k][v];
            }
        }
        return par[0][u];
    }
    int dist(int u, int v) {
        int l = query(u, v);
        return depth[u] + depth[v] - 2 * depth[l];
    }
    int parent(int u, int d) {
        for (int k = size - 1; k >= 0; k--) {
            if ((d >> k) & 1) {
                if (u != -1) u = par[k][u];
            }
        }
        return u;
    }
};

struct lca_tree_with_edge_ID {
    int n, size;
    vector<vector<pair<int, int>>> g;
    vector<vector<int>> par;
    vector<int> depth;
    lca_tree_with_edge_ID(vector<vector<pair<int, int>>> g_, int root = 0)
        : n((int)g_.size()), size(log2(n) + 2), g(g_), par(size, vector<int>(n, -1)), depth(vector<int>(n, n)) {
        queue<int> que;
        depth[root] = 0;
        que.push(root);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            for (auto [i, id] : g[p]) {
                if (depth[i] > depth[p] + 1) {
                    depth[i] = depth[p] + 1;
                    par[0][i] = p;
                    que.push(i);
                }
            }
        }
        for (int k = 0; k < size - 1; k++) {
            for (int i = 0; i < n; i++) {
                if (par[k][i] == -1)
                    par[k + 1][i] = -1;
                else
                    par[k + 1][i] = par[k][par[k][i]];
            }
        }
    }
    int query(int u, int v) {
        if (depth[u] > depth[v]) swap(u, v);
        for (int k = size - 1; k >= 0; k--) {
            if (((depth[v] - depth[u]) >> k) & 1) v = par[k][v];
            if (u == v) return u;
        }
        for (int k = size - 1; k >= 0; k--) {
            if (par[k][u] != par[k][v]) {
                u = par[k][u];
                v = par[k][v];
            }
        }
        return par[0][u];
    }
    int dist(int u, int v) {
        int l = query(u, v);
        return depth[u] + depth[v] - 2 * depth[l];
    }
};

struct UnionFind {
    vector<int> par, siz, es;
    UnionFind(int x) {
        par.resize(x);
        siz.resize(x);
        es.resize(x);
        for (int i = 0; i < x; i++) {
            par[i] = i;
            siz[i] = 1;
            es[i] = 0;
        }
    }
    int find(int x) {
        if (par[x] == x) return x;
        return par[x] = find(par[x]);
    }
    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y) {
            es[x]++;
            return false;
        }
        if (siz[x] < siz[y]) swap(x, y);
        par[y] = x;
        siz[x] += siz[y];
        es[x] += es[y] + 1;
        return true;
    }
    bool same(int x, int y) { return find(x) == find(y); }
    int size(int x) { return siz[find(x)]; }
    int edges(int x) { return es[find(x)]; }
};
struct Mo {
    int n;
    vector<pair<int, int>> lr;

    explicit Mo(int n) : n(n) {}

    void add(int l, int r) { /* [l, r) */
        lr.emplace_back(l, r);
    }

    template <typename AL, typename AR, typename EL, typename ER, typename O>
    void build(const AL& add_left, const AR& add_right, const EL& erase_left, const ER& erase_right, const O& out) {
        int q = (int)lr.size();
        int bs = n / min<int>(n, sqrt(q));
        vector<int> ord(q);
        iota(begin(ord), end(ord), 0);
        sort(begin(ord), end(ord), [&](int a, int b) {
            int ablock = lr[a].first / bs, bblock = lr[b].first / bs;
            if (ablock != bblock) return ablock < bblock;
            return (ablock & 1) ? lr[a].second > lr[b].second : lr[a].second < lr[b].second;
        });
        int l = 0, r = 0;
        for (auto idx : ord) {
            while (l > lr[idx].first) add_left(--l);
            while (r < lr[idx].second) add_right(r++);
            while (l < lr[idx].first) erase_left(l++);
            while (r > lr[idx].second) erase_right(--r);
            out(idx);
        }
    }

    template <typename A, typename E, typename O>
    void build(const A& add, const E& erase, const O& out) {
        build(add, add, erase, erase, out);
    }
};
template <class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S), F (*composition)(F, F), F (*id)()>
struct lazy_segtree {
    int _n, sz = 1;
    vector<S> dat;
    vector<F> lazy;
    lazy_segtree(vector<S> a) : _n(int(a.size())) {
        while (sz < _n) sz <<= 1;
        dat.resize(sz * 2, e());
        lazy.resize(sz * 2, id());
        rep(i, _n) dat[sz + i] = a[i];
        for (int i = sz - 1; i >= 1; i--) dat[i] = op(dat[2 * i], dat[2 * i + 1]);
    }
    void eval(int k) {
        dat[k] = mapping(lazy[k], dat[k]);
        if (k < sz) {
            lazy[k * 2] = composition(lazy[k], lazy[k * 2]);
            lazy[k * 2 + 1] = composition(lazy[k], lazy[k * 2 + 1]);
        }
        lazy[k] = id();
    }
    void apply(int a, int b, F f, int k = 1, int l = 0, int r = -1) {
        eval(k);
        if (r == -1) r = sz;
        if (r <= a || b <= l) return;
        if (a <= l && r <= b) {
            lazy[k] = composition(f, lazy[k]);
            eval(k);
            return;
        }
        int m = (l + r) >> 1;
        apply(a, b, f, 2 * k, l, m);
        apply(a, b, f, 2 * k + 1, m, r);
        dat[k] = op(dat[2 * k], dat[2 * k + 1]);
    }
    S prod(int a, int b, int k = 1, int l = 0, int r = -1) {
        eval(k);
        if (r == -1) r = sz;
        if (r <= a || b <= l) return e();
        if (a <= l && r <= b) return dat[k];
        int m = (l + r) >> 1;
        S vl = prod(a, b, 2 * k, l, m);
        S vr = prod(a, b, 2 * k + 1, m, r);
        return op(vl, vr);
    }
};
ll modinv(int x, int modulo) {
    int a = x, b = modulo, u = 1, v = 0, t;
    while (b > 0) {
        t = a / b;
        swap(a -= t * b, b);
        swap(u -= t * v, v);
    }
    return (u >= 0 ? u % modulo : (modulo - (-u) % modulo) % modulo);
}

void solve() {
    int n;
    cin >> n;
    vector<vector<int>> g(n);
    rep(i, n - 1) {
        int s, t;
        cin >> s >> t;
        s--, t--;
        g[s].push_back(t);
        g[t].push_back(s);
    }
    lca_tree lt(g);

    vector<mint> dp(n);
    vector<int> siz(n);
    function<void(int, int)> dfs_sz = [&](int v, int p) {
        siz[v] = 1;
        for (auto to : g[v]) {
            if (to != p) {
                dfs_sz(to, v);
                siz[v] += siz[to];
            }
        }
    };
    dfs_sz(0, -1);
    dp[0] = 1;
    function<void(int, int)> dfs_dp = [&](int v, int p) {
        for (auto to : g[v]) {
            if (to != p) {
                dp[to] = dp[v] * (siz[v] - siz[to]);
                dfs_dp(to, v);
            }
        }
    };
    dfs_dp(0, -1);
    int q;
    cin >> q;
    while (q--) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        int l = lt.query(u, v);
        if (v == l) swap(u, v);
        if (u == l) {
            cout << dp[v] / dp[lt.parent(v, lt.dist(l, v) - 1)] << "\n";
        } else {
            int pl = lt.parent(u, lt.dist(l, u) - 1);
            int pr = lt.parent(v, lt.dist(l, v) - 1);
            mint vl = dp[u] / dp[pl];
            mint vr = dp[v] / dp[pr];
            mint vm = n - siz[pl] - siz[pr];
            cout << vl * vr * vm << "\n";
        }
    }
}
int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    solve();
}
accuracy: 1
time_ms: 110
memory_kb: 34040
final_rank: 11

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define emb emplace_back
#define all(v) (v).begin(),(v).end()
using ll = long long;
constexpr ll MOD = 998244353;
vector<vector<int>> G;
vector<ll> sub_cnt,walk_cnt,rp;
ll modinv(ll a){
  ll b = MOD,u = 1,v = 0;
  while(b){
    ll t = a/b;
    a -= t*b;swap(a,b);
    u -= t*v;swap(u,v);
  }
  u %= MOD;
  if(u < 0) u += MOD;
  return u;
}
void dfs(int p,int bef){
  int total = 1;
  for(int nex:G[p]){
    if(nex == bef) continue;
    dfs(nex,p);total += sub_cnt[nex];
  }
  sub_cnt[p] = total;
  for(int nex:G[p]){
    if(nex == bef) continue;
    walk_cnt[nex] = total-sub_cnt[nex];
  }
}
void dfs2(int p,int bef){
  for(int nex:G[p]){
    if(nex == bef) continue;
    rp[nex] = rp[p]*walk_cnt[nex]%MOD;
    dfs2(nex,p);
  }
}
class LCA{
  int N,l2N;
  vector<int> dep;vector<vector<int>> par;
  void dfs3(int p,int bef,vector<vector<int>> &G){
    for(int i=1;i<l2N;i++) par[p][i] = par[par[p][i-1]][i-1];
    for(int nex:G[p]){
      if(nex == bef) continue;
      dep[nex] = dep[p]+1;par[nex][0] = p;dfs3(nex,p,G);
    }
  }
public:
  LCA(int I_N,vector<vector<int>> &G):N(I_N){
    l2N = 1;
    while((1<<l2N) < N) l2N++;
    dep.resize(N);par.resize(N,vector<int>(l2N));
    dfs3(0,-1,G);
  }
  int depth(int x){return dep[x];}
  int parent(int x,int len=1){
    for(int i=0;i<l2N;i++){
      if(len&(1<<i)) x = par[x][i];
    }
    return x;
  }
  int query(int x,int y){
    if(dep[x] > dep[y]) swap(x,y);
    for(int i=l2N-1;i>=0;i--){
      if(dep[y]-(1<<i) >= dep[x]) y = par[y][i];
    }
    if(x == y) return x;
    for(int i=l2N-1;i>=0;i--){
      if(par[x][i] != par[y][i]){
        x = par[x][i];y = par[y][i];
      }
    }
    return par[x][0];
  }
};

int main(){
  cin.tie(0);ios::sync_with_stdio(false);
  int N;cin >> N;
  G.resize(N);
  for(int i=0;i<N-1;i++){
    int s,t;cin >> s >> t;s--;t--;
    G[s].emb(t);G[t].emb(s);
  }
  sub_cnt.resize(N);walk_cnt.resize(N);rp.resize(N);
  dfs(0,-1);walk_cnt[0] = rp[0] = 1;dfs2(0,-1);
  // for(int i=0;i<N;i++) cout << sub_cnt[i] << (i==N-1 ? "\n":" ");
  // for(int i=0;i<N;i++) cout << walk_cnt[i] << (i==N-1 ? "\n":" ");
  // for(int i=0;i<N;i++) cout << rp[i] << (i==N-1 ? "\n":" ");
  LCA lca(N,G);
  int Q;cin >> Q;
  while(Q--){
    int u,v;cin >> u >> v;u--;v--;
    int l = lca.query(u,v);
    if(l == u || l == v){
      if(l == v) swap(u,v);
      int lc1 = lca.parent(v,lca.depth(v)-lca.depth(l)-1);
      cout << rp[v]*modinv(rp[lc1])%MOD << "\n";
    }
    else{
      int lc1_u = lca.parent(u,lca.depth(u)-lca.depth(l)-1);
      int lc1_v = lca.parent(v,lca.depth(v)-lca.depth(l)-1);
      ll ans = rp[u]*modinv(rp[lc1_u])%MOD*rp[v]%MOD*modinv(rp[lc1_v])%MOD;
      ans = ans*(N-sub_cnt[lc1_u]-sub_cnt[lc1_v])%MOD;
      cout << ans << "\n";
    }
  }
}
accuracy: 1
time_ms: 130
memory_kb: 29088
final_rank: 10

code_snippet: #include <cstdio>
#include <string>

namespace nachia{


const unsigned int INPUT_BUF_SIZE = 6 << 20;
const unsigned int OUTPUT_BUF_SIZE = 2 << 20;

char input_buf[INPUT_BUF_SIZE];

struct input_buf_init{
    input_buf_init(){
        input_buf[fread(input_buf, 1, INPUT_BUF_SIZE-1, stdin)] = '\0';
    }
} input_buf_init_instance;

struct input_buf_iterator{
private:
    unsigned int p = 0;
public:
    static bool is_whitespace(char ch){
        switch(ch){
            case ' ': case '\n': case '\r': case '\t': return true;
        }
        return false;
    }
    void skip_whitespace(){
        while(is_whitespace(input_buf[p])) p++;
    }
    unsigned int next_uint(){
        skip_whitespace();
        unsigned int buf = 0;
        while(true){
            char tmp = input_buf[p];
            if('9' < tmp || tmp < '0') break;
            buf = buf * 10 + (tmp - '0');
            p++;
        }
        return buf;
    }
    int next_int(){
        skip_whitespace();
        if(input_buf[p] == '-'){
            p++;
            return (int)(-next_uint());
        }
        return (int)next_uint();
    }
    unsigned long long next_ulong(){
        skip_whitespace();
        unsigned long long buf = 0;
        while(true){
            char tmp = input_buf[p];
            if('9' < tmp || tmp < '0') break;
            buf = buf * 10 + (tmp - '0');
            p++;
        }
        return buf;
    }
    long long next_long(){
        skip_whitespace();
        if(input_buf[p] == '-'){
            p++;
            return (long long)(-next_ulong());
        }
        return (long long)next_ulong();
    }
    char next_char(){
        skip_whitespace();
        return input_buf[p++];
    }
    std::string next_token(){
        skip_whitespace();
        std::string buf;
        while(true){
            char ch = input_buf[p];
            if(is_whitespace(ch)) break;
            buf.push_back(ch);
            p++;
        }
        return buf;
    }
};


char output_buf[OUTPUT_BUF_SIZE] = {};

struct fastoutput_table{
    char dig3lz[1000][4];
    char dig3nlz[1000][4];
    fastoutput_table(){
        for(unsigned int d=0; d<1000; d++){
            unsigned int x = d;
            unsigned int i = 0;
            dig3lz[d][i++] = ('0' + x / 100 % 10);
            dig3lz[d][i++] = ('0' + x /  10 % 10);
            dig3lz[d][i++] = ('0' + x /   1 % 10);
            dig3lz[d][i++] = '\0';
        }
        for(unsigned int d=0; d<1000; d++){
            unsigned int x = d;
            unsigned int i = 0;
            if(x >= 100) dig3nlz[d][i++] = ('0' + x / 100 % 10);
            if(x >=  10) dig3nlz[d][i++] = ('0' + x /  10 % 10);
            if(x >=   1) dig3nlz[d][i++] = ('0' + x /   1 % 10);
            dig3nlz[d][i++] = '\0';
        }
    }
} fastoutput_table_inst;

struct output_buf_iterator{
    unsigned int p = 0;
    void next_char(char c){
        output_buf[p++] = c;
    }
    void next_eoln(){
        next_char('\n');
    }
    void next_cstr(char* s){
        int i = 0;
        while(s[i]) next_char(s[i++]);
    }
    void next_dig9(unsigned int x){
        unsigned int y;
        y = x / 1'000'000;     x -= y * 1'000'000;
        next_cstr(fastoutput_table_inst.dig3lz [y]);
        y = x / 1'000;         x -= y * 1'000;
        next_cstr(fastoutput_table_inst.dig3lz [y]);
        y = x;
        next_cstr(fastoutput_table_inst.dig3lz [y]);
    }
    void next_uint(unsigned int x){
        unsigned int y = 0;
        if(x >= 1'000'000'000){
            y = x / 1'000'000'000; x -= y * 1'000'000'000;
            next_cstr(fastoutput_table_inst.dig3nlz[y]);
            next_dig9(x);
        }
        else if(x >= 1'000'000){
            y = x / 1'000'000;     x -= y * 1'000'000;
            next_cstr(fastoutput_table_inst.dig3nlz[y]);
            y = x / 1'000;         x -= y * 1'000;
            next_cstr(fastoutput_table_inst.dig3lz [y]);
            next_cstr(fastoutput_table_inst.dig3lz [x]);
        }
        else if(x >= 1'000){
            y = x / 1'000;         x -= y * 1'000;
            next_cstr(fastoutput_table_inst.dig3nlz[y]);
            next_cstr(fastoutput_table_inst.dig3lz [x]);
        }
        else if(x >= 1){
            next_cstr(fastoutput_table_inst.dig3nlz[x]);
        }
        else{
            next_char('0');
        }
    }
    void next_ulong(unsigned long long x){
        unsigned int y = 0;
        if(x >= 1'000'000'000'000'000'000){
            y = x / 1'000'000'000'000'000'000; x -= (unsigned long long)y * 1'000'000'000'000'000'000;
            next_uint(y);
            y = x / 1'000'000'000; x -= (unsigned long long)y * 1'000'000'000;
            next_dig9(y);
            next_dig9(x);
        }
        else if(x >= 1'000'000'000){
            y = x / 1'000'000'000; x -= (unsigned long long)y * 1'000'000'000;
            next_uint(y);
            next_dig9(x);
        }
        else{
            next_uint(x);
        }
    }
    void write_to_file(){
        fwrite(output_buf, p, 1, stdout);
    }
};

} // namespace nachia


#include <vector>
#include <algorithm>


#include <utility>

namespace nachia{
    
struct AdjacencyList{
public:
    struct AdjacencyListRange{
        using iterator = typename std::vector<int>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const int& operator[](int i) const { return begi[i]; }
    };
private:
    int mn;
    std::vector<int> E;
    std::vector<int> I;
public:
    AdjacencyList(int n, std::vector<std::pair<int,int>> edges, bool rev){
        mn = n;
        std::vector<int> buf(n+1, 0);
        for(auto [u,v] : edges){ ++buf[u]; if(rev) ++buf[v]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        E.resize(buf[n]);
        for(int i=(int)edges.size()-1; i>=0; i--){
            auto [u,v] = edges[i];
            E[--buf[u]] = v;
            if(rev) E[--buf[v]] = u;
        }
        I = std::move(buf);
    }
    AdjacencyList(const std::vector<std::vector<int>>& edges = {}){
        int n = mn = edges.size();
        std::vector<int> buf(n+1, 0);
        for(int i=0; i<n; i++) buf[i+1] = buf[i] + edges[i].size();
        E.resize(buf[n]);
        for(int i=0; i<n; i++) for(int j=0; j<(int)edges[i].size(); j++) E[buf[i]+j] = edges[i][j];
        I = std::move(buf);
    }
    static AdjacencyList from_raw(std::vector<int> targets, std::vector<int> bounds){
        AdjacencyList res;
        res.mn = bounds.size() - 1;
        res.E = std::move(targets);
        res.I = std::move(bounds);
        return res;
    }
    AdjacencyListRange operator[](int u) const {
        return AdjacencyListRange{ E.begin() + I[u], E.begin() + I[u+1] };
    }
    int num_vertices() const { return mn; }
    int size() const { return num_vertices(); }
    int num_edges() const { return E.size(); }
    AdjacencyList reversed_edges() const {
        AdjacencyList res;
        int n = res.mn = mn;
        std::vector<int> buf(n+1, 0);
        for(int v : E) ++buf[v];
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.E.resize(buf[n]);
        for(int u=0; u<n; u++) for(int v : operator[](u)) res.E[--buf[v]] = u;
        res.I = std::move(buf);
        return res;
    }
};

struct AdjacencyListEdgeIndexed{
public:
    struct Edge { int to; int edgeidx; };
    struct AdjacencyListRange{
        using iterator = typename std::vector<Edge>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const Edge& operator[](int i) const { return begi[i]; }
    };
private:
    int mn;
    std::vector<Edge> E;
    std::vector<int> I;
public:
    AdjacencyListEdgeIndexed(int n, const std::vector<std::pair<int,int>>& edges, bool rev){
        mn = n;
        std::vector<int> buf(n+1, 0);
        for(auto [u,v] : edges){ ++buf[u]; if(rev) ++buf[v]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        E.resize(buf[n]);
        for(int i=(int)edges.size()-1; i>=0; i--){
            auto [u,v] = edges[i];
            E[--buf[u]] = { v, i };
            if(rev) E[--buf[v]] = { u, i };
        }
        I = std::move(buf);
    }
    AdjacencyListEdgeIndexed() : AdjacencyListEdgeIndexed(0, {}, false) {}
    AdjacencyListRange operator[](int u) const {
        return AdjacencyListRange{ E.begin() + I[u], E.begin() + I[u+1] };
    }
    int num_vertices() const { return mn; }
    int size() const { return num_vertices(); }
    int num_edges() const { return E.size(); }
    AdjacencyListEdgeIndexed reversed_edges() const {
        AdjacencyListEdgeIndexed res;
        int n = res.mn = mn;
        std::vector<int> buf(n+1, 0);
        for(auto [v,i] : E) ++buf[v];
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.E.resize(buf[n]);
        for(int u=0; u<n; u++) for(auto [v,i] : operator[](u)) res.E[--buf[v]] = {u,i};
        res.I = std::move(buf);
        return res;
    }
};

} // namespace nachia

namespace nachia{

struct HeavyLightDecomposition{
private:

    int N;
    std::vector<int> P;
    std::vector<int> PP;
    std::vector<int> PD;
    std::vector<int> D;
    std::vector<int> I;

    std::vector<int> rangeL;
    std::vector<int> rangeR;

public:

    HeavyLightDecomposition(const AdjacencyList& E = AdjacencyList(1, {}, false)){
        N = E.num_vertices();
        P.assign(N, -1);
        I = {0};
        I.reserve(N);
        for(int i=0; i<(int)I.size(); i++){
            int p = I[i];
            for(int e : E[p]) if(P[p] != e){
                I.push_back(e);
                P[e] = p;
            }
        }
        std::vector<int> Z(N, 1);
        std::vector<int> nx(N, -1);
        PP.resize(N);
        for(int i=0; i<N; i++) PP[i] = i;
        for(int i=N-1; i>=1; i--){
            int p = I[i];
            Z[P[p]] += Z[p];
            if(nx[P[p]] == -1) nx[P[p]] = p;
            if(Z[nx[P[p]]] < Z[p]) nx[P[p]] = p;
        }

        for(int p : I) if(nx[p] != -1) PP[nx[p]] = p;

        PD.assign(N,N);
        PD[0] = 0;
        D.assign(N,0);
        for(int p : I) if(p != 0){
            PP[p] = PP[PP[p]];
            PD[p] = std::min(PD[PP[p]], PD[P[p]]+1);
            D[p] = D[P[p]]+1;
        }
        
        rangeL.assign(N,0);
        rangeR.assign(N,0);
        
        for(int p : I){
            rangeR[p] = rangeL[p] + Z[p];
            int ir = rangeR[p];
            for(int e : E[p]) if(P[p] != e) if(e != nx[p]){
                rangeL[e] = (ir -= Z[e]);
            }
            if(nx[p] != -1){
                rangeL[nx[p]] = rangeL[p] + 1;
            }
        }

        I.resize(N);
        for(int i=0; i<N; i++) I[rangeL[i]] = i;
    }

    int depth(int p) const { return D[p]; }
    int to_seq(int vertex) const { return rangeL[vertex]; }
    int to_vtx(int seqidx) const { return I[seqidx]; }
    int parent_of(int v) const { return P[v]; }
    int heavy_root_of(int v) const { return PP[v]; }
    int heavy_child_of(int v) const {
        if(to_seq(v) == N-1) return -1;
        int cand = to_vtx(to_seq(v) + 1);
        if(PP[v] == PP[cand]) return cand;
        return v;
    }

    int lca(int u, int v) const {
        if(PD[u] < PD[v]) std::swap(u, v);
        while(PD[u] > PD[v]) u = P[PP[u]];
        while(PP[u] != PP[v]){ u = P[PP[u]]; v = P[PP[v]]; }
        return (D[u] > D[v]) ? v : u;
    }

    int dist(int u, int v) const {
        return depth(u) + depth(v) - depth(lca(u,v)) * 2;
    }

    std::vector<std::pair<int,int>> path(int r, int c, bool include_root = true, bool reverse_path = false) const {
        if(PD[c] < PD[r]) return {};
        std::vector<std::pair<int,int>> res(PD[c]-PD[r]+1);
        for(int i=0; i<(int)res.size()-1; i++){
            res[i] = std::make_pair(rangeL[PP[c]], rangeL[c]+1);
            c = P[PP[c]];
        }
        if(PP[r] != PP[c] || D[r] > D[c]) return {};
        res.back() = std::make_pair(rangeL[r]+(include_root?0:1), rangeL[c]+1);
        if(res.back().first == res.back().second) res.pop_back();
        if(!reverse_path) std::reverse(res.begin(),res.end());
        else for(auto& a : res) a = std::make_pair(N - a.second, N - a.first);
        return move(res);
    }

    std::pair<int,int> subtree(int p){
        return std::make_pair(rangeL[p], rangeR[p]);
    }

    int median(int x, int y, int z) const {
        return lca(x,y) ^ lca(y,z) ^ lca(x,z);
    }

    int la(int from, int to, int d) const {
        if(d < 0) return -1;
        int g = lca(from,to);
        int dist0 = D[from] - D[g] * 2 + D[to];
        if(dist0 < d) return -1;
        int p = from;
        if(D[from] - D[g] < d){ p = to; d = dist0 - d; }
        while(D[p] - D[PP[p]] < d){
            d -= D[p] - D[PP[p]] + 1;
            p = P[PP[p]];
        }
        return I[rangeL[p] - d];
    }
};

} // namespace nachia


namespace nachia{

template<unsigned int MOD>
struct StaticModint{
private:
    using u64 = unsigned long long;
    unsigned int x;
public:

    using my_type = StaticModint;
    template< class Elem >
    static Elem safe_mod(Elem x){
        if(x < 0){
            if(0 <= x+MOD) return x + MOD;
            return MOD - ((-(x+MOD)-1) % MOD + 1);
        }
        return x % MOD;
    }

    StaticModint() : x(0){}
    StaticModint(const my_type& a) : x(a.x){}
    template< class Elem >
    StaticModint(Elem v) : x(safe_mod(v)){}
    unsigned int operator*() const { return x; }
    my_type& operator+=(const my_type& r){ auto t = x + r.x; if(t >= MOD) t -= MOD; x = t; return *this; }
    my_type operator+(const my_type& r) const { my_type res = *this; return res += r; }
    my_type& operator-=(const my_type& r){ auto t = x + MOD - r.x; if(t >= MOD) t -= MOD; x = t; return *this; }
    my_type operator-(const my_type& r) const { my_type res = *this; return res -= r; }
    my_type operator-() const { my_type res = *this; res.x = ((res.x == 0) ? 0 : (MOD - res.x)); return res; }
    my_type& operator*=(const my_type& r){ x = (u64)x * r.x % MOD; return *this; }
    my_type operator*(const my_type& r) const { my_type res = *this; return res *= r; }
    my_type pow(unsigned long long i) const {
        my_type a = *this, res = 1;
        while(i){ if(i & 1) res *= a; a *= a; i >>= 1; }
        return res;
    }
    my_type inv() const { return pow(MOD-2); }
    unsigned int val() const { return x; }
    static unsigned int get_mod() { return MOD; }
    my_type& operator/=(const my_type& r){ return operator*=(r.inv()); }
    my_type operator/(const my_type& r) const { return operator*(r.inv()); }
};

}

#include <iostream>
#include <string>
#include <array>
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<(int)(n); i++)

const i64 INF = 1001001001001001001;

const u32 MOD = 998244353;

int main(){
    nachia::input_buf_iterator iitr;
    nachia::output_buf_iterator oitr;

    int N = iitr.next_uint();
    vector<pair<int,int>> edges(N-1);
    rep(i,N-1){
        int u = iitr.next_uint();
        int v = iitr.next_uint();
        u--; v--;
        edges[i] = make_pair(u,v);
    }

    nachia::HeavyLightDecomposition hld(nachia::AdjacencyList(N, edges, true));

    using Modint = nachia::StaticModint<MOD>;
    vector<int> s(N);
    for(int i=0; i<N; i++) s[i] = hld.subtree(i).second - hld.subtree(i).first;
    
    vector<Modint> inv_table(N+1, Modint(1));
    for(int i=2; i<=N; i++) inv_table[i] = -inv_table[MOD%i] * (MOD/i);

    vector<Modint> Prod(N, Modint(1));
    vector<Modint> inv_Prod(N, Modint(1));
    for(int seq=1; seq<N; seq++){
        int v = hld.to_vtx(seq);
        Prod[v] = Prod[hld.parent_of(v)] * (s[hld.parent_of(v)] - s[v]);
        inv_Prod[v] = inv_Prod[hld.parent_of(v)] * inv_table[s[hld.parent_of(v)] - s[v]];
    }

    int Q = iitr.next_uint();
    rep(qi, Q){
        int u = iitr.next_uint();
        int v = iitr.next_uint();
        u--; v--;
        Modint ans = 1;
        if(hld.depth(u) > hld.depth(v)) swap(u,v);
        int g = hld.lca(u,v);
        if(hld.parent_of(v) == u){
            ans = 1;
        }
        else if(g == u){
            int v_p = hld.la(v, g, hld.depth(v) - hld.depth(g) - 1);
            ans = inv_Prod[v_p] * Prod[v];
        }
        else{
            int u_p = hld.la(u, g, hld.depth(u) - hld.depth(g) - 1);
            int v_p = hld.la(v, g, hld.depth(v) - hld.depth(g) - 1);
            ans = Modint(N - s[u_p] - s[v_p]);
            ans *= inv_Prod[u_p] * Prod[u];
            ans *= inv_Prod[v_p] * Prod[v];
        }
        oitr.next_uint(ans.val());
        oitr.next_eoln();
    }
    oitr.write_to_file();
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 13380
final_rank: 3

code_snippet: #include <vector>
#include <algorithm>


#include <utility>

namespace nachia{
    
struct AdjacencyList{
public:
    struct AdjacencyListRange{
        using iterator = typename std::vector<int>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const int& operator[](int i) const { return begi[i]; }
    };
private:
    int mn;
    std::vector<int> E;
    std::vector<int> I;
public:
    AdjacencyList(int n, std::vector<std::pair<int,int>> edges, bool rev){
        mn = n;
        std::vector<int> buf(n+1, 0);
        for(auto [u,v] : edges){ ++buf[u]; if(rev) ++buf[v]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        E.resize(buf[n]);
        for(int i=(int)edges.size()-1; i>=0; i--){
            auto [u,v] = edges[i];
            E[--buf[u]] = v;
            if(rev) E[--buf[v]] = u;
        }
        I = std::move(buf);
    }
    AdjacencyList(const std::vector<std::vector<int>>& edges = {}){
        int n = mn = edges.size();
        std::vector<int> buf(n+1, 0);
        for(int i=0; i<n; i++) buf[i+1] = buf[i] + edges[i].size();
        E.resize(buf[n]);
        for(int i=0; i<n; i++) for(int j=0; j<(int)edges[i].size(); j++) E[buf[i]+j] = edges[i][j];
        I = std::move(buf);
    }
    static AdjacencyList from_raw(std::vector<int> targets, std::vector<int> bounds){
        AdjacencyList res;
        res.mn = bounds.size() - 1;
        res.E = std::move(targets);
        res.I = std::move(bounds);
        return res;
    }
    AdjacencyListRange operator[](int u) const {
        return AdjacencyListRange{ E.begin() + I[u], E.begin() + I[u+1] };
    }
    int num_vertices() const { return mn; }
    int size() const { return num_vertices(); }
    int num_edges() const { return E.size(); }
    AdjacencyList reversed_edges() const {
        AdjacencyList res;
        int n = res.mn = mn;
        std::vector<int> buf(n+1, 0);
        for(int v : E) ++buf[v];
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.E.resize(buf[n]);
        for(int u=0; u<n; u++) for(int v : operator[](u)) res.E[--buf[v]] = u;
        res.I = std::move(buf);
        return res;
    }
};

struct AdjacencyListEdgeIndexed{
public:
    struct Edge { int to; int edgeidx; };
    struct AdjacencyListRange{
        using iterator = typename std::vector<Edge>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const Edge& operator[](int i) const { return begi[i]; }
    };
private:
    int mn;
    std::vector<Edge> E;
    std::vector<int> I;
public:
    AdjacencyListEdgeIndexed(int n, const std::vector<std::pair<int,int>>& edges, bool rev){
        mn = n;
        std::vector<int> buf(n+1, 0);
        for(auto [u,v] : edges){ ++buf[u]; if(rev) ++buf[v]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        E.resize(buf[n]);
        for(int i=(int)edges.size()-1; i>=0; i--){
            auto [u,v] = edges[i];
            E[--buf[u]] = { v, i };
            if(rev) E[--buf[v]] = { u, i };
        }
        I = std::move(buf);
    }
    AdjacencyListEdgeIndexed() : AdjacencyListEdgeIndexed(0, {}, false) {}
    AdjacencyListRange operator[](int u) const {
        return AdjacencyListRange{ E.begin() + I[u], E.begin() + I[u+1] };
    }
    int num_vertices() const { return mn; }
    int size() const { return num_vertices(); }
    int num_edges() const { return E.size(); }
    AdjacencyListEdgeIndexed reversed_edges() const {
        AdjacencyListEdgeIndexed res;
        int n = res.mn = mn;
        std::vector<int> buf(n+1, 0);
        for(auto [v,i] : E) ++buf[v];
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.E.resize(buf[n]);
        for(int u=0; u<n; u++) for(auto [v,i] : operator[](u)) res.E[--buf[v]] = {u,i};
        res.I = std::move(buf);
        return res;
    }
};

} // namespace nachia

namespace nachia{

struct HeavyLightDecomposition{
private:

    int N;
    std::vector<int> P;
    std::vector<int> PP;
    std::vector<int> PD;
    std::vector<int> D;
    std::vector<int> I;

    std::vector<int> rangeL;
    std::vector<int> rangeR;

public:

    HeavyLightDecomposition(const AdjacencyList& E = AdjacencyList(1, {}, false)){
        N = E.num_vertices();
        P.assign(N, -1);
        I = {0};
        I.reserve(N);
        for(int i=0; i<(int)I.size(); i++){
            int p = I[i];
            for(int e : E[p]) if(P[p] != e){
                I.push_back(e);
                P[e] = p;
            }
        }
        std::vector<int> Z(N, 1);
        std::vector<int> nx(N, -1);
        PP.resize(N);
        for(int i=0; i<N; i++) PP[i] = i;
        for(int i=N-1; i>=1; i--){
            int p = I[i];
            Z[P[p]] += Z[p];
            if(nx[P[p]] == -1) nx[P[p]] = p;
            if(Z[nx[P[p]]] < Z[p]) nx[P[p]] = p;
        }

        for(int p : I) if(nx[p] != -1) PP[nx[p]] = p;

        PD.assign(N,N);
        PD[0] = 0;
        D.assign(N,0);
        for(int p : I) if(p != 0){
            PP[p] = PP[PP[p]];
            PD[p] = std::min(PD[PP[p]], PD[P[p]]+1);
            D[p] = D[P[p]]+1;
        }
        
        rangeL.assign(N,0);
        rangeR.assign(N,0);
        
        for(int p : I){
            rangeR[p] = rangeL[p] + Z[p];
            int ir = rangeR[p];
            for(int e : E[p]) if(P[p] != e) if(e != nx[p]){
                rangeL[e] = (ir -= Z[e]);
            }
            if(nx[p] != -1){
                rangeL[nx[p]] = rangeL[p] + 1;
            }
        }

        I.resize(N);
        for(int i=0; i<N; i++) I[rangeL[i]] = i;
    }

    int depth(int p) const { return D[p]; }
    int to_seq(int vertex) const { return rangeL[vertex]; }
    int to_vtx(int seqidx) const { return I[seqidx]; }
    int parent_of(int v) const { return P[v]; }
    int heavy_root_of(int v) const { return PP[v]; }
    int heavy_child_of(int v) const {
        if(to_seq(v) == N-1) return -1;
        int cand = to_vtx(to_seq(v) + 1);
        if(PP[v] == PP[cand]) return cand;
        return v;
    }

    int lca(int u, int v) const {
        if(PD[u] < PD[v]) std::swap(u, v);
        while(PD[u] > PD[v]) u = P[PP[u]];
        while(PP[u] != PP[v]){ u = P[PP[u]]; v = P[PP[v]]; }
        return (D[u] > D[v]) ? v : u;
    }

    int dist(int u, int v) const {
        return depth(u) + depth(v) - depth(lca(u,v)) * 2;
    }

    std::vector<std::pair<int,int>> path(int r, int c, bool include_root = true, bool reverse_path = false) const {
        if(PD[c] < PD[r]) return {};
        std::vector<std::pair<int,int>> res(PD[c]-PD[r]+1);
        for(int i=0; i<(int)res.size()-1; i++){
            res[i] = std::make_pair(rangeL[PP[c]], rangeL[c]+1);
            c = P[PP[c]];
        }
        if(PP[r] != PP[c] || D[r] > D[c]) return {};
        res.back() = std::make_pair(rangeL[r]+(include_root?0:1), rangeL[c]+1);
        if(res.back().first == res.back().second) res.pop_back();
        if(!reverse_path) std::reverse(res.begin(),res.end());
        else for(auto& a : res) a = std::make_pair(N - a.second, N - a.first);
        return move(res);
    }

    std::pair<int,int> subtree(int p){
        return std::make_pair(rangeL[p], rangeR[p]);
    }

    int median(int x, int y, int z) const {
        return lca(x,y) ^ lca(y,z) ^ lca(x,z);
    }

    int la(int from, int to, int d) const {
        if(d < 0) return -1;
        int g = lca(from,to);
        int dist0 = D[from] - D[g] * 2 + D[to];
        if(dist0 < d) return -1;
        int p = from;
        if(D[from] - D[g] < d){ p = to; d = dist0 - d; }
        while(D[p] - D[PP[p]] < d){
            d -= D[p] - D[PP[p]] + 1;
            p = P[PP[p]];
        }
        return I[rangeL[p] - d];
    }
};

} // namespace nachia


namespace nachia{

template<unsigned int MOD>
struct StaticModint{
private:
    using u64 = unsigned long long;
    unsigned int x;
public:

    using my_type = StaticModint;
    template< class Elem >
    static Elem safe_mod(Elem x){
        if(x < 0){
            if(0 <= x+MOD) return x + MOD;
            return MOD - ((-(x+MOD)-1) % MOD + 1);
        }
        return x % MOD;
    }

    StaticModint() : x(0){}
    StaticModint(const my_type& a) : x(a.x){}
    template< class Elem >
    StaticModint(Elem v) : x(safe_mod(v)){}
    unsigned int operator*() const { return x; }
    my_type& operator+=(const my_type& r){ auto t = x + r.x; if(t >= MOD) t -= MOD; x = t; return *this; }
    my_type operator+(const my_type& r) const { my_type res = *this; return res += r; }
    my_type& operator-=(const my_type& r){ auto t = x + MOD - r.x; if(t >= MOD) t -= MOD; x = t; return *this; }
    my_type operator-(const my_type& r) const { my_type res = *this; return res -= r; }
    my_type operator-() const { my_type res = *this; res.x = ((res.x == 0) ? 0 : (MOD - res.x)); return res; }
    my_type& operator*=(const my_type& r){ x = (u64)x * r.x % MOD; return *this; }
    my_type operator*(const my_type& r) const { my_type res = *this; return res *= r; }
    my_type pow(unsigned long long i) const {
        my_type a = *this, res = 1;
        while(i){ if(i & 1) res *= a; a *= a; i >>= 1; }
        return res;
    }
    my_type inv() const { return pow(MOD-2); }
    unsigned int val() const { return x; }
    static unsigned int get_mod() { return MOD; }
    my_type& operator/=(const my_type& r){ return operator*=(r.inv()); }
    my_type operator/(const my_type& r) const { return operator*(r.inv()); }
};

}

#include <iostream>
#include <string>
#include <array>
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<(int)(n); i++)

const i64 INF = 1001001001001001001;

const u32 MOD = 998244353;

int main(){
    int N; cin >> N;
    vector<pair<int,int>> edges(N-1);
    rep(i,N-1){
        int u,v; cin >> u >> v; u--; v--;
        edges[i] = make_pair(u,v);
    }

    nachia::HeavyLightDecomposition hld(nachia::AdjacencyList(N, edges, true));

    using Modint = nachia::StaticModint<MOD>;
    vector<int> s(N);
    for(int i=0; i<N; i++) s[i] = hld.subtree(i).second - hld.subtree(i).first;
    
    vector<Modint> inv_table(N+1, Modint(1));
    for(int i=2; i<=N; i++) inv_table[i] = -inv_table[MOD%i] * (MOD/i);

    vector<Modint> Prod(N, Modint(1));
    vector<Modint> inv_Prod(N, Modint(1));
    for(int seq=1; seq<N; seq++){
        int v = hld.to_vtx(seq);
        Prod[v] = Prod[hld.parent_of(v)] * (s[hld.parent_of(v)] - s[v]);
        inv_Prod[v] = inv_Prod[hld.parent_of(v)] * inv_table[s[hld.parent_of(v)] - s[v]];
    }

    int Q; cin >> Q;
    rep(qi, Q){
        int u,v; cin >> u >> v; u--; v--;
        Modint ans = 1;
        if(hld.depth(u) > hld.depth(v)) swap(u,v);
        int g = hld.lca(u,v);
        if(hld.parent_of(v) == u){
            ans = 1;
        }
        else if(g == u){
            int v_p = hld.la(v, g, hld.depth(v) - hld.depth(g) - 1);
            ans = inv_Prod[v_p] * Prod[v];
        }
        else{
            int u_p = hld.la(u, g, hld.depth(u) - hld.depth(g) - 1);
            int v_p = hld.la(v, g, hld.depth(v) - hld.depth(g) - 1);
            ans = Modint(N - s[u_p] - s[v_p]);
            ans *= inv_Prod[u_p] * Prod[u];
            ans *= inv_Prod[v_p] * Prod[v];
        }
        cout << ans.val() << '\n';
    }
    return 0;
}


struct ios_do_not_sync{
    ios_do_not_sync(){
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
    }
} ios_do_not_sync_instance;
accuracy: 1
time_ms: 40
memory_kb: 9288
final_rank: 1

code_snippet: #include <vector>
#include <algorithm>


#include <utility>

namespace nachia{
    
struct AdjacencyList{
public:
    struct AdjacencyListRange{
        using iterator = typename std::vector<int>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const int& operator[](int i) const { return begi[i]; }
    };
private:
    int mn;
    std::vector<int> E;
    std::vector<int> I;
public:
    AdjacencyList(int n, std::vector<std::pair<int,int>> edges, bool rev){
        mn = n;
        std::vector<int> buf(n+1, 0);
        for(auto [u,v] : edges){ ++buf[u]; if(rev) ++buf[v]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        E.resize(buf[n]);
        for(int i=(int)edges.size()-1; i>=0; i--){
            auto [u,v] = edges[i];
            E[--buf[u]] = v;
            if(rev) E[--buf[v]] = u;
        }
        I = std::move(buf);
    }
    AdjacencyList(const std::vector<std::vector<int>>& edges = {}){
        int n = mn = edges.size();
        std::vector<int> buf(n+1, 0);
        for(int i=0; i<n; i++) buf[i+1] = buf[i] + edges[i].size();
        E.resize(buf[n]);
        for(int i=0; i<n; i++) for(int j=0; j<(int)edges[i].size(); j++) E[buf[i]+j] = edges[i][j];
        I = std::move(buf);
    }
    static AdjacencyList from_raw(std::vector<int> targets, std::vector<int> bounds){
        AdjacencyList res;
        res.mn = bounds.size() - 1;
        res.E = std::move(targets);
        res.I = std::move(bounds);
        return res;
    }
    AdjacencyListRange operator[](int u) const {
        return AdjacencyListRange{ E.begin() + I[u], E.begin() + I[u+1] };
    }
    int num_vertices() const { return mn; }
    int size() const { return num_vertices(); }
    int num_edges() const { return E.size(); }
    AdjacencyList reversed_edges() const {
        AdjacencyList res;
        int n = res.mn = mn;
        std::vector<int> buf(n+1, 0);
        for(int v : E) ++buf[v];
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.E.resize(buf[n]);
        for(int u=0; u<n; u++) for(int v : operator[](u)) res.E[--buf[v]] = u;
        res.I = std::move(buf);
        return res;
    }
};

struct AdjacencyListEdgeIndexed{
public:
    struct Edge { int to; int edgeidx; };
    struct AdjacencyListRange{
        using iterator = typename std::vector<Edge>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const Edge& operator[](int i) const { return begi[i]; }
    };
private:
    int mn;
    std::vector<Edge> E;
    std::vector<int> I;
public:
    AdjacencyListEdgeIndexed(int n, const std::vector<std::pair<int,int>>& edges, bool rev){
        mn = n;
        std::vector<int> buf(n+1, 0);
        for(auto [u,v] : edges){ ++buf[u]; if(rev) ++buf[v]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        E.resize(buf[n]);
        for(int i=(int)edges.size()-1; i>=0; i--){
            auto [u,v] = edges[i];
            E[--buf[u]] = { v, i };
            if(rev) E[--buf[v]] = { u, i };
        }
        I = std::move(buf);
    }
    AdjacencyListEdgeIndexed() : AdjacencyListEdgeIndexed(0, {}, false) {}
    AdjacencyListRange operator[](int u) const {
        return AdjacencyListRange{ E.begin() + I[u], E.begin() + I[u+1] };
    }
    int num_vertices() const { return mn; }
    int size() const { return num_vertices(); }
    int num_edges() const { return E.size(); }
    AdjacencyListEdgeIndexed reversed_edges() const {
        AdjacencyListEdgeIndexed res;
        int n = res.mn = mn;
        std::vector<int> buf(n+1, 0);
        for(auto [v,i] : E) ++buf[v];
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.E.resize(buf[n]);
        for(int u=0; u<n; u++) for(auto [v,i] : operator[](u)) res.E[--buf[v]] = {u,i};
        res.I = std::move(buf);
        return res;
    }
};

} // namespace nachia

namespace nachia{

struct HeavyLightDecomposition{
private:

    int N;
    std::vector<int> P;
    std::vector<int> PP;
    std::vector<int> PD;
    std::vector<int> D;
    std::vector<int> I;

    std::vector<int> rangeL;
    std::vector<int> rangeR;

public:

    HeavyLightDecomposition(const AdjacencyList& E = AdjacencyList(1, {}, false)){
        N = E.num_vertices();
        P.assign(N, -1);
        I = {0};
        I.reserve(N);
        for(int i=0; i<(int)I.size(); i++){
            int p = I[i];
            for(int e : E[p]) if(P[p] != e){
                I.push_back(e);
                P[e] = p;
            }
        }
        std::vector<int> Z(N, 1);
        std::vector<int> nx(N, -1);
        PP.resize(N);
        for(int i=0; i<N; i++) PP[i] = i;
        for(int i=N-1; i>=1; i--){
            int p = I[i];
            Z[P[p]] += Z[p];
            if(nx[P[p]] == -1) nx[P[p]] = p;
            if(Z[nx[P[p]]] < Z[p]) nx[P[p]] = p;
        }

        for(int p : I) if(nx[p] != -1) PP[nx[p]] = p;

        PD.assign(N,N);
        PD[0] = 0;
        D.assign(N,0);
        for(int p : I) if(p != 0){
            PP[p] = PP[PP[p]];
            PD[p] = std::min(PD[PP[p]], PD[P[p]]+1);
            D[p] = D[P[p]]+1;
        }
        
        rangeL.assign(N,0);
        rangeR.assign(N,0);
        
        for(int p : I){
            rangeR[p] = rangeL[p] + Z[p];
            int ir = rangeR[p];
            for(int e : E[p]) if(P[p] != e) if(e != nx[p]){
                rangeL[e] = (ir -= Z[e]);
            }
            if(nx[p] != -1){
                rangeL[nx[p]] = rangeL[p] + 1;
            }
        }

        I.resize(N);
        for(int i=0; i<N; i++) I[rangeL[i]] = i;
    }

    int depth(int p) const { return D[p]; }
    int to_seq(int vertex) const { return rangeL[vertex]; }
    int to_vtx(int seqidx) const { return I[seqidx]; }
    int parent_of(int v) const { return P[v]; }
    int heavy_root_of(int v) const { return PP[v]; }
    int heavy_child_of(int v) const {
        if(to_seq(v) == N-1) return -1;
        int cand = to_vtx(to_seq(v) + 1);
        if(PP[v] == PP[cand]) return cand;
        return v;
    }

    int lca(int u, int v) const {
        if(PD[u] < PD[v]) std::swap(u, v);
        while(PD[u] > PD[v]) u = P[PP[u]];
        while(PP[u] != PP[v]){ u = P[PP[u]]; v = P[PP[v]]; }
        return (D[u] > D[v]) ? v : u;
    }

    int dist(int u, int v) const {
        return depth(u) + depth(v) - depth(lca(u,v)) * 2;
    }

    std::vector<std::pair<int,int>> path(int r, int c, bool include_root = true, bool reverse_path = false) const {
        if(PD[c] < PD[r]) return {};
        std::vector<std::pair<int,int>> res(PD[c]-PD[r]+1);
        for(int i=0; i<(int)res.size()-1; i++){
            res[i] = std::make_pair(rangeL[PP[c]], rangeL[c]+1);
            c = P[PP[c]];
        }
        if(PP[r] != PP[c] || D[r] > D[c]) return {};
        res.back() = std::make_pair(rangeL[r]+(include_root?0:1), rangeL[c]+1);
        if(res.back().first == res.back().second) res.pop_back();
        if(!reverse_path) std::reverse(res.begin(),res.end());
        else for(auto& a : res) a = std::make_pair(N - a.second, N - a.first);
        return move(res);
    }

    std::pair<int,int> subtree(int p){
        return std::make_pair(rangeL[p], rangeR[p]);
    }

    int median(int x, int y, int z) const {
        return lca(x,y) ^ lca(y,z) ^ lca(x,z);
    }

    int la(int from, int to, int d) const {
        if(d < 0) return -1;
        int g = lca(from,to);
        int dist0 = D[from] - D[g] * 2 + D[to];
        if(dist0 < d) return -1;
        int p = from;
        if(D[from] - D[g] < d){ p = to; d = dist0 - d; }
        while(D[p] - D[PP[p]] < d){
            d -= D[p] - D[PP[p]] + 1;
            p = P[PP[p]];
        }
        return I[rangeL[p] - d];
    }
};

} // namespace nachia


namespace nachia{

template<unsigned int MOD>
struct StaticModint{
private:
    using u64 = unsigned long long;
    unsigned int x;
public:

    using my_type = StaticModint;
    template< class Elem >
    static Elem safe_mod(Elem x){
        if(x < 0){
            if(0 <= x+MOD) return x + MOD;
            return MOD - ((-(x+MOD)-1) % MOD + 1);
        }
        return x % MOD;
    }

    StaticModint() : x(0){}
    StaticModint(const my_type& a) : x(a.x){}
    template< class Elem >
    StaticModint(Elem v) : x(safe_mod(v)){}
    unsigned int operator*() const { return x; }
    my_type& operator+=(const my_type& r){ auto t = x + r.x; if(t >= MOD) t -= MOD; x = t; return *this; }
    my_type operator+(const my_type& r) const { my_type res = *this; return res += r; }
    my_type& operator-=(const my_type& r){ auto t = x + MOD - r.x; if(t >= MOD) t -= MOD; x = t; return *this; }
    my_type operator-(const my_type& r) const { my_type res = *this; return res -= r; }
    my_type operator-() const { my_type res = *this; res.x = ((res.x == 0) ? 0 : (MOD - res.x)); return res; }
    my_type& operator*=(const my_type& r){ x = (u64)x * r.x % MOD; return *this; }
    my_type operator*(const my_type& r) const { my_type res = *this; return res *= r; }
    my_type pow(unsigned long long i) const {
        my_type a = *this, res = 1;
        while(i){ if(i & 1) res *= a; a *= a; i >>= 1; }
        return res;
    }
    my_type inv() const { return pow(MOD-2); }
    unsigned int val() const { return x; }
    static unsigned int get_mod() { return MOD; }
    my_type& operator/=(const my_type& r){ return operator*=(r.inv()); }
    my_type operator/(const my_type& r) const { return operator*(r.inv()); }
};

}

#include <iostream>
#include <string>
#include <array>
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<(int)(n); i++)

const i64 INF = 1001001001001001001;

int main(){
    int N; cin >> N;
    vector<pair<int,int>> edges(N-1);
    rep(i,N-1){
        int u,v; cin >> u >> v; u--; v--;
        edges[i] = make_pair(u,v);
    }

    nachia::HeavyLightDecomposition hld(nachia::AdjacencyList(N, edges, true));

    using Modint = nachia::StaticModint<998244353>;
    vector<int> s(N);
    for(int i=0; i<N; i++) s[i] = hld.subtree(i).second - hld.subtree(i).first;

    vector<Modint> Prod(N, Modint(1));
    for(int seq=1; seq<N; seq++){
        int v = hld.to_vtx(seq);
        Prod[v] = Prod[hld.parent_of(v)] * (s[hld.parent_of(v)] - s[v]);
    }
    
    vector<Modint> inv_Prod(N, Modint(1));
    for(int i=0; i<N; i++) inv_Prod[i] = Prod[i].inv();

    int Q; cin >> Q;
    rep(qi, Q){
        int u,v; cin >> u >> v; u--; v--;
        Modint ans = 1;
        if(hld.depth(u) > hld.depth(v)) swap(u,v);
        int g = hld.lca(u,v);
        if(hld.parent_of(v) == u){
            ans = 1;
        }
        else if(g == u){
            int v_p = hld.la(v, g, hld.depth(v) - hld.depth(g) - 1);
            ans = inv_Prod[v_p] * Prod[v];
        }
        else{
            int u_p = hld.la(u, g, hld.depth(u) - hld.depth(g) - 1);
            int v_p = hld.la(v, g, hld.depth(v) - hld.depth(g) - 1);
            ans = Modint(N - s[u_p] - s[v_p]);
            ans *= inv_Prod[u_p] * Prod[u];
            ans *= inv_Prod[v_p] * Prod[v];
        }
        cout << ans.val() << '\n';
    }
    return 0;
}


struct ios_do_not_sync{
    ios_do_not_sync(){
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
    }
} ios_do_not_sync_instance;
accuracy: 1
time_ms: 50
memory_kb: 9416
final_rank: 2

code_snippet: #include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <vector>
#include <numeric>
#include <algorithm>
#include <queue>
#include <string>
#include <random>
#include <array>
#include <climits>
#include <map>
#include <cassert>
#include <stack>
#include <iomanip>
#include <cfloat>

constexpr int MOD = 998244353;

int main() {
	int n; std::cin >> n;
	std::vector<std::pair<int, int>> edges(n - 1);
	for (auto& [u, v] : edges) {
		std::cin >> u >> v; --u; --v;
	}
	int q; std::cin >> q;
	std::vector<std::pair<int, int>> queries(q);
	for (auto& [u, v] : queries) {
		std::cin >> u >> v; --u; --v;
	}
	std::vector<std::vector<int>> graph(n);
	for (const auto [u, v] : edges) {
		graph[u].push_back(v);
		graph[v].push_back(u);
	}
	std::vector<int> depth(n, -1), order;
	std::queue<int> queue;
	std::vector<std::vector<int>> doubling(n);
	depth[0] = 0;
	queue.push(0);
	while (!queue.empty()) {
		const auto top = queue.front(); queue.pop();
		order.push_back(top);
		for (const auto next : graph[top]) {
			if (depth[next] >= 0) continue;
			depth[next] = depth[top] + 1;
			queue.push(next);
			int parent = top;
			doubling[next].push_back(parent);
			while (doubling[next].size() <= doubling[parent].size()) {
				parent = doubling[parent][doubling[next].size() - 1];
				doubling[next].push_back(parent);
			}
		}
	}
	const auto ancestor = [&doubling](int node, const int diff) {
		for (int idx = 0; idx < doubling[node].size(); ++idx) {
			if ((diff >> idx) & 1) {
				node = doubling[node][idx];
			}
		}
		return node;
	};
	const auto lca = [&depth, &doubling, &ancestor](int i, int j) {
		if (depth[i] < depth[j]) {
			const int diff = depth[j] - depth[i];
			j = ancestor(j, diff);
		}
		else if (depth[i] > depth[j]) {
			const int diff = depth[i] - depth[j];
			i = ancestor(i, diff);
		}
		if (i == j) return i;
		for (int idx = doubling[i].size() - 1; idx >= 0; --idx) {
			if (idx < doubling[i].size() && doubling[i][idx] != doubling[j][idx]) {
				i = doubling[i][idx];
				j = doubling[j][idx];
			}
		}
		return doubling[i][0];
	};
	std::reverse(order.begin(), order.end());
	std::vector<int> size(n, 1);
	for (const auto node : order) {
		if (node == 0) continue;
		size[doubling[node][0]] += size[node];
	}
	std::reverse(order.begin(), order.end());
	std::vector<std::vector<long long int>> doubling_count(n);
	for (const auto node : order) {
		if (node == 0) continue;
		doubling_count[node].push_back(size[doubling[node][0]] - size[node]);
		for (auto idx = 0; idx + 1 < doubling[node].size(); ++idx) {
			doubling_count[node].push_back(doubling_count[doubling[node][idx]][idx] * doubling_count[node][idx] % MOD);
		}
	}
	const auto calc_pass = [&doubling_count, &doubling](int node, const int diff) {
		long long int result{ 1 };
		for (auto idx = 0; idx < doubling_count[node].size(); ++idx) {
			if ((diff >> idx) & 1) {
				result = result * doubling_count[node][idx] % MOD;
				node = doubling[node][idx];
			}
		}
		return result;
	};
	for (const auto [u, v] : queries) {
		const auto a = lca(u, v);
		long long int result{ 1 };
		if (a != u) {
			result = result * calc_pass(u, depth[u] - depth[a] - 1) % MOD;
		}
		if (a != v) {
			result = result * calc_pass(v, depth[v] - depth[a] - 1) % MOD;
		}
		if (a != u && a != v) {
			const auto prev_u = ancestor(u, depth[u] - depth[a] - 1);
			const auto prev_v = ancestor(v, depth[v] - depth[a] - 1);
			result = result * (size[0] - size[prev_u] - size[prev_v]) % MOD;
		}
		std::cout << result << '\n';
	}
}
accuracy: 1
time_ms: 190
memory_kb: 44060
final_rank: 15

code_snippet: #include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <vector>
#include <numeric>
#include <algorithm>
#include <queue>
#include <string>
#include <random>
#include <array>
#include <climits>
#include <map>
#include <cassert>
#include <stack>
#include <iomanip>
#include <cfloat>

constexpr int MOD = 998244353;

int main() {
	int n; std::cin >> n;
	std::vector<std::pair<int, int>> edges(n - 1);
	for (auto& [u, v] : edges) {
		std::cin >> u >> v; --u; --v;
	}
	int q; std::cin >> q;
	std::vector<std::pair<int, int>> queries(q);
	for (auto& [u, v] : queries) {
		std::cin >> u >> v; --u; --v;
	}
	std::vector<std::vector<int>> graph(n);
	for (const auto [u, v] : edges) {
		graph[u].push_back(v);
		graph[v].push_back(u);
	}
	std::vector<int> depth(n, -1), order;
	std::queue<int> queue;
	std::vector<std::vector<int>> doubling(n);
	depth[0] = 0;
	queue.push(0);
	while (!queue.empty()) {
		const auto top = queue.front(); queue.pop();
		order.push_back(top);
		for (const auto next : graph[top]) {
			if (depth[next] >= 0) continue;
			depth[next] = depth[top] + 1;
			queue.push(next);
			int parent = top;
			doubling[next].push_back(parent);
			while (doubling[next].size() <= doubling[parent].size()) {
				parent = doubling[parent][doubling[next].size() - 1];
				doubling[next].push_back(parent);
			}
		}
	}
	const auto ancestor = [&doubling](int node, const int diff) {
		for (int idx = 0; idx < doubling[node].size(); ++idx) {
			if ((diff >> idx) & 1) {
				node = doubling[node][idx];
			}
		}
		return node;
	};
	const auto lca = [&depth, &doubling, &ancestor](int i, int j) {
		if (depth[i] < depth[j]) {
			const int diff = depth[j] - depth[i];
			j = ancestor(j, diff);
		}
		else if (depth[i] > depth[j]) {
			const int diff = depth[i] - depth[j];
			i = ancestor(i, diff);
		}
		if (i == j) return i;
		for (int idx = doubling[i].size() - 1; idx >= 0; --idx) {
			if (doubling[i][idx] != doubling[j][idx]) {
				i = doubling[i][idx];
				j = doubling[j][idx];
			}
		}
		return doubling[i][0];
	};
	std::reverse(order.begin(), order.end());
	std::vector<int> size(n, 1);
	for (const auto node : order) {
		if (node == 0) continue;
		size[doubling[node][0]] += size[node];
	}
	std::reverse(order.begin(), order.end());
	std::vector<std::vector<long long int>> doubling_count(n);
	for (const auto node : order) {
		if (node == 0) continue;
		doubling_count[node].push_back(size[doubling[node][0]] - size[node]);
		for (auto idx = 0; idx + 1 < doubling[node].size(); ++idx) {
			doubling_count[node].push_back(doubling_count[doubling[node][idx]][idx] * doubling_count[node][idx] % MOD);
		}
	}
	const auto calc_pass = [&doubling_count, &doubling](int node, const int diff) {
		long long int result{ 1 };
		for (auto idx = 0; idx < doubling_count[node].size(); ++idx) {
			if ((diff >> idx) & 1) {
				result = result * doubling_count[node][idx] % MOD;
				node = doubling[node][idx];
			}
		}
		return result;
	};
	for (const auto [u, v] : queries) {
		const auto a = lca(u, v);
		long long int result{ 1 };
		if (a != u) {
			result = result * calc_pass(u, depth[u] - depth[a] - 1) % MOD;
		}
		if (a != v) {
			result = result * calc_pass(v, depth[v] - depth[a] - 1) % MOD;
		}
		if (a != u && a != v) {
			const auto prev_u = ancestor(u, depth[u] - depth[a] - 1);
			const auto prev_v = ancestor(v, depth[v] - depth[a] - 1);
			result = result * (size[0] - size[prev_u] - size[prev_v]) % MOD;
		}
		std::cout << result << '\n';
	}
}
accuracy: 0.85
time_ms: 170
memory_kb: 44256
final_rank: 20

code_snippet: #include<iostream>
#include<string>
#include<iomanip>
#include<cmath>
#include<vector>
#include<algorithm>

using namespace std;

#define int long long

constexpr int MOD = 998244353;
constexpr int INF = (1<<30);


struct edge{
	int to, num;
	
	edge(int to = 0, int num = 0): to(to), num(num) {}
	edge(const edge &e) { to = e.to; num = e.num;};
	
	bool operator < (const edge &e) const {
		return num < e.num;
	}
};


vector<vector<edge>> G;


vector<int> con, num, c;
vector<int> depth;
vector<vector<int>> table;

void dfs(int node, int per, int dep, int &n){
	
	table[0][node] = per;
	depth[node] = dep;
	con[node] = 1;
	num[node] = n++;
	
	for(edge &e : G[node]){
		if(e.to == per) {
			e.num = -1;
			continue;
		}
		dfs(e.to, node, dep+1, n);
		con[node] += con[e.to];
		e.num = num[e.to];
	}
}

void dfs2(int node, int per){
	
	for(edge &e : G[node]){
		if(e.to == per) {
			continue;
		}
		
		c[e.to] = c[node] * (MOD + con[node] - con[e.to]) % MOD;
		dfs2(e.to, node);
	}
}

void init(int V){
	
	int logV = 1;
	
	for(int i = 1; i <= V; i <<= 1, logV++);
	
	depth.resize(V+1);
	table.resize(logV, vector<int>(V+1,-1));
	con.resize(V+1);
	num.resize(V+1);
	c.resize(V+1, 1);
	
	int n = 0;
	
	dfs(1, -1, 0, n);
	dfs2(1, -1);
	
	for(int k = 0; k + 1 < logV; k++){
		for(int v = 0; v <= V; v++){
			if(table[k][v] < 0) table[k+1][v] = -1;
			else table[k+1][v] = table[k][table[k][v]];
		}
	}
}

int lca(int u, int v){
	
	if(depth[u] > depth[v]) swap(u, v);
	for(int k = 0; k < table.size(); k++){
		if((depth[v] - depth[u]) >> k & 1){
			v = table[k][v];
		}
	}
	
	if(u == v) return u; 
	
	for(int k = table.size()-1; k >= 0; k--){
		if(table[k][u] != table[k][v]){
			u = table[k][u];
			v = table[k][v];
		}
	}
	
	return table[0][u];
}

long long power(long long x, long long n){
	long long ans = 1;
	for(;n;n >>= 1, x *= x, ans %= MOD, x %= MOD) if(n&1)ans*=x;
	return ans % MOD;
}

signed main(){
	cin.tie(nullptr);
	ios::sync_with_stdio(false);
	
	int N, Q;
	
	cin>>N;
	
	G.resize(N+1);
	
	for(int i = 0; i < N-1; i++){
		int s, t;
		cin>>s>>t;
		
		G[s].push_back(edge(t, 0));
		G[t].push_back(edge(s, 0));
	}
	
	init(N+1);
	
	for(int i = 1; i <= N; i++){
		sort(G[i].begin(), G[i].end());
	}
	
	cin>>Q;
	
	for(int i = 0; i < Q; i++){
		int u, v;
		
		cin>>u>>v;
		
		if(depth[u] > depth[v]) swap(u, v);
		
		int w = lca(u, v), ans, a = -2, b = -2;
		
		b = upper_bound(G[w].begin(), G[w].end(), edge(0, num[v])) - G[w].begin();
		b = G[w][b-1].to;
		
		if(u == w) {
			ans = c[v] * power(c[b], MOD-2) % MOD;
		} else {
			a = upper_bound(G[w].begin(), G[w].end(), edge(0, num[u])) - G[w].begin();
			a = G[w][a-1].to;
			
			ans = c[v] * c[u] % MOD;
			ans = (ans * ((MOD + con[w]%MOD - con[a]%MOD - con[b]%MOD + N - con[w]%MOD) % MOD)) % MOD;
			ans = (ans * power((c[a] * c[b]) % MOD, MOD-2)) % MOD;
		}
		
		cout<<ans<<endl;
	}
	
	return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 35156
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
//#define MOD 1000000007
#define EPS 0.000000001


#define MOD 998244353
#define SIZE 100005


struct Info{
	Info(int arg_node_id,int arg_DEP){
		node_id = arg_node_id;
		DEP = arg_DEP;
	}
	bool operator<(const struct Info& arg) const{

		return DEP > arg.DEP; //深さの■降順■
	}
	int node_id,DEP;
};

struct Data{
	int parent,head,depth;
	ll size;
};

int N;
int IND,num_chain = 0;
int INDEX[SIZE];
ll K;
Data DATA[SIZE];
vector<int> G[SIZE];
vector<Info> info[SIZE];
map<int,int> HEAD; //HEAD[headのnode番号] := 鎖のid
map<int,pair<int,int>> MAP; //MAP[ノード番号] = (鎖のid,鎖の中でのindex)
ll** rui;
ll num_nodes[SIZE];


//LCA
int root = 0;
int MAX_LOG_V = 17;
int POW[18];

int PARENT[18][SIZE],DEPTH[SIZE];

void rec(int node,int pre){

	num_nodes[node] = 1;

	for(int i = 0; i < G[node].size(); i++){

		int child = G[node][i];
		if(child == pre)continue;

		rec(child,node);
		num_nodes[node] += num_nodes[child];
	}
}

int getChain_id(int head){

	auto at = HEAD.find(head);
	if(at == HEAD.end()){

		HEAD[head] = num_chain++;
	}

	return HEAD[head];
}


int makeTree(int node_id,int pre,int depth){

	PARENT[0][node_id] = pre;
	DEPTH[node_id] = depth;

	DATA[node_id].depth = depth; //深さ
	DATA[node_id].parent = pre; //親
	DATA[node_id].size = 1; //部分木のノード数(自分&子孫)

	int child;

	for(int i = 0; i < G[node_id].size(); i++){

		child = G[node_id][i];
		if(child == pre)continue;

		DATA[node_id].size += makeTree(child,node_id,depth+1);
	}

	return DATA[node_id].size;
}

void HLD(int node_id,int head,int pre){

	INDEX[node_id] = IND++;
	DATA[node_id].head = head; //node_idが属する鎖のhead

	int chain_id = getChain_id(head);
	info[chain_id].push_back(Info(node_id,DEPTH[node_id]));


	//子の中で、最大の重み(部分木のノード数)を持つものを探す
	int maxi = -BIG_NUM;
	int max_node = -1;

	for(int i = 0; i < G[node_id].size(); i++){

		int child = G[node_id][i];
		if(child == pre)continue;

		if(maxi < DATA[child].size){

			maxi = DATA[child].size;
			max_node = child;
		}
	}

	if(max_node == -1){ //子なし

		return;
	}

	//最大の重みを持つ子へ(headは変わらず:同じ鎖の上だから)
	HLD(max_node,head,node_id);

	//その他の子を処理(新しい鎖を作る)
	for(int i = 0; i < G[node_id].size(); i++){

		int child = G[node_id][i];
		if(child == pre || child == max_node)continue;

		HLD(child,child,node_id);
	}
}

int lca(int left,int right){

	if(DEPTH[left] > DEPTH[right])swap(left,right);

	for(int k = MAX_LOG_V-1; k >= 0; k--){
		if(DEPTH[right]-DEPTH[left] >= POW[k]){
			right = PARENT[k][right];
		}
	}

	if(left == right)return left;

	for(int k = MAX_LOG_V-1; k >= 0; k--){
		if(PARENT[k][left] == PARENT[k][right]){
			//Do nothing
		}else{
			left = PARENT[k][left];
			right = PARENT[k][right];
		}
	}
	return PARENT[0][left];
}

ll extgcd(ll a,ll b,ll &x,ll &y){
	ll d = a;
	if(b != 0){
		d = extgcd(b,a%b,y,x);
		y -= (a/b)*x;
	}else{
		x = 1;
		y = 0;
	}
	return d;
}

ll mod_inverse(ll a,ll m){
    ll x,y;
    extgcd(a,m,x,y);
    return (m+x%m)%m;
}


ll calc(int start,int goal){

	int now = DATA[start].parent;

	//startの1つ上からgoalの1つ手前までの場合の数を掛けていく

	if(now == goal){

		return 1;
	}

	int base_depth = DEPTH[goal]+1;
	ll ret = num_nodes[now]-num_nodes[start];

	while(true){

		int head = DATA[now].head;
		int chain_id = MAP[now].first;
		int from = MAP[now].second;

		if(DEPTH[head] >= base_depth){ //鎖の端まで掛けて良い

			int to = MAP[head].second;
			ll mult = rui[chain_id][to]*mod_inverse(rui[chain_id][from],MOD);
			mult %= MOD;

			ret *= mult;
			ret %= MOD;

			if(DEPTH[head] == base_depth){

				return ret;
			}

			now = head;

		}else{ //鎖上にgoalの1つ手間がある

			int to = MAP[goal].second-1;
			ll mult = rui[chain_id][to]*mod_inverse(rui[chain_id][from],MOD);

			mult %= MOD;

			ret *= mult;
			ret %= MOD;

			return ret;

		}

		//現在headにいる(次の鎖へ)
		int tmp_p = PARENT[0][head];
		ret *= num_nodes[tmp_p]-num_nodes[head];

		ret %= MOD;

		now = tmp_p;
	}

	return ret;
}

//fromからgoalへ向かう際の、goalの1つ手前のノードを取得する関数
int get_pre_node(int from,int goal){

	int from_depth = DEPTH[from];
	int to_depth = DEPTH[goal]+1;

	if(from_depth == to_depth){

		return from;
	}

	int now = from;

	int diff = from_depth-to_depth;

	for(int i = MAX_LOG_V-1; i >= 0; i--){
		if(diff < POW[i])continue;

		diff -= POW[i];
		now = PARENT[i][now];

		if(diff == 0)break;
	}

	return now;

}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= MAX_LOG_V; i++){

		POW[i] = POW[i-1]*2;
	}

	scanf("%d",&N);

	int a,b;

	for(int i = 0; i < N-1; i++){

		scanf("%d %d",&a,&b);

		a--;
		b--;

		G[a].push_back(b);
		G[b].push_back(a);
	}

	rec(root,-1);
	makeTree(root,-1,0); //深さ,親,部分木サイズ計算
	IND = 0;
	HLD(root,root,-1);  //鎖の作成(0スタートでdfs木を作ったので、0がrootとなる)

	//lca計算用
	for(int k = 0; k + 1 < MAX_LOG_V; k++){
		for(int node_id = 0; node_id < N; node_id++){
			if(PARENT[k][node_id] < 0){

				PARENT[k+1][node_id] = -1;

			}else{

				PARENT[k+1][node_id] = PARENT[k][PARENT[k][node_id]];
			}
		}
	}

	rui = new ll*[num_chain];

	//鎖ごとに、経路数の累積積を作る
	for(int i = 0; i < num_chain; i++){

		sort(info[i].begin(),info[i].end());

		for(int k = 0; k < info[i].size(); k++){

			MAP[info[i][k].node_id] = make_pair(i,k+1);
		}

		rui[i] = new ll [info[i].size()+1];

		rui[i][0] = 1; //ダミー
		rui[i][1] = 1;
		int pre = info[i][0].node_id;

		for(int k = 1; k < info[i].size(); k++){

			//pre方向以外の部分木サイズ
			int now = info[i][k].node_id;
			ll num = num_nodes[now]-num_nodes[pre];
			rui[i][k+1] = num;
			rui[i][k+1] *= rui[i][k];
			rui[i][k+1] %= MOD;

			pre = now;
		}
	}

	int num_Q;
	scanf("%d",&num_Q);

	ll ans;
	ll ALL = N;

	for(int loop = 0; loop < num_Q; loop++){

		scanf("%d %d",&a,&b);
		a--;
		b--;

		int LCA = lca(a,b);

		if(LCA == a || LCA == b){

			if(LCA == a){

				swap(a,b); //bを根方向にする
			}

			ans = calc(a,b);

		}else{

			ans = (calc(a,LCA)*calc(b,LCA))%MOD;

			//■■パス上の親の1つ手前までの部分木サイズを引く■■
			int pre_a = get_pre_node(a,LCA);
			int pre_b = get_pre_node(b,LCA);

			ll mult = (ALL-num_nodes[LCA]); //根方向
			mult += (num_nodes[LCA]-(num_nodes[pre_a]+num_nodes[pre_b])); //パス以外の葉方向

			ans *= mult;
			ans %= MOD;
		}

		printf("%lld\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 550
memory_kb: 38564
final_rank: 19

code_snippet: #include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
#include <functional>
using namespace std;

//  last common ancestor
class LCA
{
    int n;
public:
    vector<int> D;
    vector<vector<int>> P;

    LCA(vector<vector<int>> E, int root)
    {
        n = (int)E.size();
        P = vector<vector<int>>(n);
        D = vector<int>(n);

        function<void (int, int, int)> f = [&](int c, int p, int d)
        {
            D[c] = d;

            if (d>0)
                P[c].push_back(p);
            for (int i=1; 1<<i<=d; i++)
                P[c].push_back(P[P[c][i-1]][i-1]);

            for (int e: E[c])
                if (e != p)
                    f(e, c, d+1);
        };
        f(root, -1, 0);
    }

    int query(int a, int b)
    {
        if (D[a]>D[b])
            swap(a, b);

        int d = D[b]-D[a];
        for (int i=0; d>0; i++)
        {
            if (d&1)
                b = P[b][i];
            d >>= 1;
        }

        if (a==b)
            return a;

        int i = 0;
        while (1<<(i+1)<=D[a])
            i++;
        for (; i>=0; i--)
            if (1<<i<=D[a] && P[a][i]!=P[b][i])
            {
                a = P[a][i];
                b = P[b][i];
            }

        if (D[a]>0)
            a = P[a][0];
        return a;
    }
};

//  a^b % m
long long powmod(long long a, long long b, long long m)
{
    long long r = 1;
    for (; b>0; b>>=1, a=a*a%m)
        if (b&1)
            r = r*a%m;
    return r;
}

//  mを法とするxの逆数
long long inv(long long x, long long m)
{
    return powmod(x, m-2, m);
}

int main()
{
    int N;
    cin>>N;
    vector<vector<int>> E(N);
    for (int i=0; i<N-1; i++)
    {
        int s, t;
        cin>>s>>t;
        E[s-1].push_back(t-1);
        E[t-1].push_back(s-1);
    }

    LCA lca(E, 0);
    //  D[x]: 頂点xの深さ
    vector<int> D = lca.D;
    //  P[x][y]: 頂点xの1<<y個上の頂点
    vector<vector<int>> P = lca.P;

    //  S[x]: 頂点xを根とする部分木の頂点数
    vector<int> S(N);
    function<void(int, int)> fS = [&](int c, int p)
    {
        S[c] = 1;
        for (int e: E[c])
            if (e!=p)
            {
                fS(e, c);
                S[c] += S[e];
            }
    };
    fS(0, -1);

    //  頂点xの祖先で深さがdの頂点を返す
    function<int(int, int)> ancestor = [&](int x, int d)
    {
        int d2 = D[x]-d;
        for (int i=0; d2>0; i++, d2>>=1)
            if (d2&1)
                x = P[x][i];
        return x;
    };

    long long MOD = 998244353;

    //  T[x]: 根を自宅、会社を頂点xとしたときの問題の条件を満たす通勤経路数
    vector<long long> T(N);
    function<void(int, int)> fT = [&](int c, int p)
    {
        if (p==-1 || p==0)
            T[c] = 1;
        else
            T[c] = T[p]*(S[p]-S[c])%MOD;
        for (int e: E[c])
            if (e!=p)
                fT(e, c);
    };
    fT(0, -1);

    int Q;
    cin>>Q;
    for (int q=0; q<Q; q++)
    {
        int u, v;
        cin>>u>>v;
        u--, v--;

        //  最小共通祖先
        int a = lca.query(u, v);
        if (u==a)
        {
            //  vがuの子孫
            int pv = ancestor(v, D[a]+1);
            cout<<T[v]*inv(T[pv], MOD)%MOD<<endl;
        }
        else if (v==a)
        {
            //  uがvの子孫
            int pu = ancestor(u, D[a]+1);
            cout<<T[u]*inv(T[pu], MOD)%MOD<<endl;
        }
        else
        {
            //  最小共通祖先からuやvに向かって1個辿った頂点
            int pu = ancestor(u, D[a]+1);
            int pv = ancestor(v, D[a]+1);

            //  uからaに向かう途中の寄り道／aからvに向かう途中の寄り道
            long long au = T[u]*inv(T[pu], MOD)%MOD;
            long long av = T[v]*inv(T[pv], MOD)%MOD;
            //  aでの寄り道
            long long aa = N-S[pu]-S[pv];

            cout<<au*av%MOD*aa%MOD<<endl;
        }
    }
}
accuracy: 1
time_ms: 320
memory_kb: 41972
final_rank: 17