树形dp

考虑以 为根的子树

  1. 先考虑 的每个儿子对于答案的贡献,明显是各个子树大小之和。
  2. 再考虑跨越根节点 的各个子树之间的答案,先任意找两棵子树 ,假设他们的根节点为 他们之间产生的答案是

这里的 是子树上各个节点深度之和,这样单独一棵子树 对答案的贡献就可以很好的算出来了,这里用 代表子树的集合

下面贴代码

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define int long long
#define endl '\n'
#define rep(i,a,b) for(int i = a ; i <= b ; i++)
#define per(i,a,b) for(int i = a ; i >= b ; i--)
using namespace std;
const int MOD = 998244353;
const int MAXN = 2e5 + 10;
int alldeepth[MAXN],si[MAXN];
vector<int> graph[MAXN];
int ans = 0;
void dfs(int u,int fa) {
    si[u] = 1;
    int sum = 0;
    int num = 0;
    for (auto& v : graph[u]) {
        if (v == fa)continue;
        dfs(v,u);
        alldeepth[u] += alldeepth[v];
        si[u] += si[v];
        sum = (sum + si[v])%MOD;
        ans = (ans + si[v]) % MOD;
        num++;
    }
    alldeepth[u] += si[u];
    if (num <= 1)return;
    for (auto& v : graph[u]) {
        if (v == fa)continue;
        ans = (ans + ((sum - si[v])%MOD + MOD) % MOD * alldeepth[v] % MOD) % MOD;
    }
}
void solve() {
    int n;
    cin >> n;
    ans = 0;
    rep(i,0,n) {
        graph[i].clear();
        alldeepth[i] = 0;
        si[i] = 0;
    }
    rep(i,1,n-1) {
        int u,v;
        cin >> u >> v;
        graph[u].push_back(v);
        graph[v].push_back(u);
    }
    dfs(1,0);
    cout << ans << endl;
}
signed main() {
    IOS;
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}