dsu on tree
const int N = 2e5 + 5;int n;
int dp[N];
vector<int> adj[N];int siz[N], ms[N], p[N];
void init() { for (int i = 1; i <= n; i++) { siz[i] = ms[i] = p[i] = 0; adj[i].clear(); }}
void dfs1(int now, int fa) { siz[now] = 1; ms[now] = -1; p[now] = fa; for (auto t : adj[now]) { if (t == fa) continue; dfs1(t, now); siz[now] += siz[t]; if (ms[now] == -1 || siz[t] > siz[ms[now]]) ms[now] = t; }}
// 计算 v 的子树对 dp[u] 的贡献void cal_ans(int u, int v, int now, int fa) { // do sth
for (auto t : adj[now]) { if (t == fa) continue; cal_ans(u, v, t, now); }}
// 将 v 的子树加入已知集合void add(int u, int v, int now, int fa) { // do sth
for (auto t : adj[now]) { if (t == fa) continue; add(u, v, t, now); }}
void del(int now, int fa) { // do sth
for (auto t : adj[now]) { if (t == fa) continue; del(t, now); }}
void dfs(int now, int fa, bool keep) { for (auto t : adj[now]) { if (t == fa || t == ms[now]) continue; dfs(t, now, 0); }
if (ms[now] != -1) { dfs(ms[now], now, 1); }
// 考虑清楚 dp[now] 与 dp[t] 的关系是什么?求和还是取 max
for (auto t : adj[now]) { if (t == fa || t == ms[now]) continue; cal_ans(now, t, t, now); add(now, t, t, now); }
// 结算 now
if (keep == 0) { del(now, fa); }}