#ifdef poe #define debug(x) cerr<<#x<<": "< using namespace std; using ll=long long; using ull=unsigned long long; using ld=long double; using pi=pair; using pll=pair; using str=string; templateusing vec=vector; using vi=vec;using vvi=vec;using vvvi=vec;using vvvvi=vec;using vvvvvi=vec; using vll=vec;using vvll=vec;using vvvll=vec;using vvvvll=vec;using vvvvvll=vec; using vpi=vec;using vvpi=vec;using vvvpi=vec;using vvvvpi=vec;using vvvvvpi=vec; using vpll=vec;using vvpll=vec;using vvvpll=vec;using vvvvpll=vec;using vvvvvpll=vec; templateusing pq=priority_queue>; templateusing pqg=priority_queue,greater>; #define rep(i,n) for(int i=0;i<(int)(n);i++) #define rep1(i,n) for(int i=1;i<=(int)(n);i++) #define loop(i, l, r) for (int i=(int)(l); i<(int)(r); i++) #define per(i,n) for(int i=(int)(n)-1;0<=i;i--) #define per1(i,n) for(int i=(int)(n);0>(i))&1) #define pf push_front #define pb push_back #define df pop_front #define db pop_back #define fi first #define se second #define elif else if #define Yes cout<<"Yes"<<'\n' #define No cout<<"No"<<'\n' #define YN(x) cout<<((x)?"Yes":"No")<<'\n' #define O(x) cout<<(x)<<'\n' #define ismid(a,b,c) ((a)<=(b)&&(b)<(c)) templatebool chmin(S&a,T b){if(a>b){a=b;return true;}return false;} templatebool chmax(S&a,T b){if(abool next_combination(T l,T r,int k){T m=l+k;if(l==r||l==m||r==m)return false;T t=m;while(l!=t){t--;if(*t<*(r-1)){T d=m;while(*t>=*d)d++;iter_swap(t,d);rotate(t+1,d+1,r);rotate(m,m+(r-d)-1,r);return true;}}rotate(l,m,r);return false;} templateT Min(T a,T b){return aT Min(T a,T b,Args...args){return Min(Min(a,b),args...);} templateT Max(T a,T b){return a>b?a:b;} templateT Max(T a,T b,Args...args){return Max(Max(a,b),args...);} templateT Sum(T a){return a;} templateT Sum(T a,Args... args){return a+Sum(args...);} templateT Max(const vector&v){return *max_element(all(v));} templateT Min(const vector&v){return *min_element(all(v));} templateT Sum(const vector&v){return accumulate(all(v),T(0));} templateT Max(const pair&p){return max(p.first,p.second);} templateT Min(const pair&p){return min(p.first,p.second);} templateT Sum(const pair&p){return p.first+p.second;} templateistream&operator>>(istream&s,pair&p){s>>p.first>>p.second;return s;} templateostream&operator<<(ostream&s,pair&p){s<istream&operator>>(istream&s,vector&v){for(auto&i:v)s>>i;return s;} templateostream&operator<<(ostream&s,vector&v){for(int i=0;i<(int)v.size();i++)s< struct edge { int from, to; T cost; int id; }; // 頂点の構造体 vector> template using edges = vector>; // グラフの構造体 graph template struct graph { bool isdirected, isweighted; edges _edges; vector> data; T sumcost; graph() = default; // 頂点数 n のグラフを作成する graph(int n) : isdirected(directed), isweighted(weighted), data(n), sumcost(T{}) {} // from から to へ辺を追加する void add_edge(int from, int to, T cost = 1, int id = -1) { if (id == -1) id = _edges.size(); data[from].push_back(edge{from, to, cost, id}); _edges.push_back(edge{from, to, cost, id}); if (!isdirected) { data[to].push_back(edge{to, from, cost, id}); } sumcost += cost; } // 辺を追加する void add_edge(edge _e) { add_edge(_e.from, _e.to, _e.cost, _e.id); } // 標準入力から辺を読み込む void read(int m, int indexed = 1) { for (int i=0; i> from >> to; if (isweighted) cin >> cost; add_edge(from - indexed, to - indexed, cost); } } // 頂点数を返す int size() { return data.size(); } // 頂点を返す edges operator[](int k) { return data[k]; } // パスを頂点に変換する vector path_to_vertex(edges& _e) { vector re; if (_e.size() == 0) { return re; } if (_e.size() == 1) { re.push_back(_e[0].from); re.push_back(_e[0].to); return re; } int x=_e[0].from,y=_e[0].to; if (x==_e[1].to || x == _e[1].from) swap(x, y); re.push_back(x); for (int i=1; i<_e.size(); i++) { re.push_back(y); x = _e[i].to; if (x == y) x = _e[i].from; swap(x, y); } return re; } // 頂点をパスに変換する edges vetex_to_path (vector& v){ edges re; for (int i=0; i+1 vector dfs_order(graph& g, int s = 0) { vector re(g.size(), -1); stack q; q.push(s); int cnt = 0; re[s] = cnt++; while (!q.empty()) { int x = q.top(); q.pop(); for (auto e : g[x]) { if (re[e.to] == -1) { re[e.to] = cnt++; q.push(e.to); } } } return re; } template vector bfs_order(graph& g, int s = 0) { vector re(g.size(), -1); queue q; q.push(s); int cnt = 0; re[s] = cnt++; while (!q.empty()) { int x = q.front(); q.pop(); for (auto e : g[x]) { if (re[e.to] == -1) { re[e.to] = cnt++; q.push(e.to); } } } return re; } template vector distance(graph& g, int s = 0) { vector re(g.size(), -1); queue q; q.push(s); re[s] = 0; while (!q.empty()) { int x = q.front(); q.pop(); for (auto e : g[x]) { if (re[e.to] == -1) { re[e.to] = re[x] + 1; q.push(e.to); } } } return re; } template pair> diameter(graph& g) { vector d1 = distance(g, 0); int s = max_element(d1.begin(), d1.end()) - d1.begin(); vector d2 = distance(g, s); int t = max_element(d2.begin(), d2.end()) - d2.begin(); return {d2[t], {s, t}}; } int main() { IO(); int T=1; cin >> T; while (T--) solve(); } #include using namespace atcoder; using mint = modint998244353; void solve() { int n; cin >> n; graph g(n); g.read(n-1); mint ans = 0; vi b = bfs_order(g); vpi c(n); rep(i, n) c[i] = {b[i], i}; troS(c); vi d = distance(g); vec> dp(n, vec(4)); range2(_, i, c) { dp[i][0] = 1; range(e, g[i]) if (d[i] < d[e.to]) { rep(j, 3) ans += dp[i][j] * dp[e.to][2-j]; rep(j, 3) dp[i][j+1] += dp[e.to][j]; } } cout << ans.val() << nl; }