题解 [AT_dp_v]
AT_dp_v Subtree
题目大意
给出结点数为
思路
显然是换根 dp。
首先考虑一个根节点的情况,设
考虑换根,设
然而要对
考虑暴力相乘,设
于是问题变成如何求
想不到前缀后缀积怎么办?
不难想到分治,设
先将区间
当
最终答案即为
空间虽然小了点,但时间复杂度为
Code:
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define lp(i, j, n) for(int i = j; i <= n; ++i)
#define dlp(i, n, j) for(int i = n; i >= j; --i)
#define mst(n, v) memset(n, v, sizeof(n))
#define mcy(n, v) memcpy(n, v, sizeof(v))
#define INF 1e18
#define MAX4 0x3f3f3f3f
#define MAX8 0x3f3f3f3f3f3f3f3f
#define pii pair<int, int>
#define pll pair<ll, ll>
#define co(x) cerr << (x) << ' '
#define cod(x) cerr << (x) << endl
#define fi first
#define se second
#define eps 1e-8
#define lc(x) ((x) << 1)
#define rc(x) ((x) << 1 ^ 1)
#define pb(x) emplace_back(x)
using namespace std;
const int N = 100010;
int n, m;
int f[N], g[N];
struct edge { int v, nxt; } E[N << 1];
int en, hd[N];
void add(int u, int v) { E[++en] = { v, hd[u] }, hd[u] = en; }
void dfs1(int u, int fa) {
f[u] = 1;
for(int i = hd[u]; i; i = E[i].nxt) {
int v = E[i].v;
if(v == fa) continue;
dfs1(v, u), f[u] = 1ll * f[u] * (f[v] + 1) % m;
}
}
int son[N], tot;
ll mul;
void solve(int l, int r) {
if(l == r) return g[son[l]] = (mul + 1) % m, void();
ll t = mul; int mid = l + r >> 1;
lp(i, mid + 1, r) mul = mul * (f[son[i]] + 1) % m;
solve(l, mid);
mul = t; lp(i, l, mid) mul = mul * (f[son[i]] + 1) % m;
solve(mid + 1, r);
}
void dfs2(int u, int fa) {
tot = 0, mul = g[u];
for(int i = hd[u]; i; i = E[i].nxt) {
if(E[i].v != fa) son[++tot] = E[i].v;
}
if(tot >= 1) solve(1, tot);
for(int i = hd[u]; i; i = E[i].nxt) {
if(E[i].v != fa) dfs2(E[i].v, u);
}
}
signed main() {
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
#ifndef READ
ios::sync_with_stdio(false);
cin.tie(0);
#endif
cin >> n >> m;
int u, v;
lp(i, 1, n - 1) cin >> u >> v, add(u, v), add(v, u);
dfs1(1, 0), g[1] = 1, dfs2(1, 0);
lp(i, 1, n) cout << 1ll * f[i] * g[i] % m << endl;
return 0;
}