题意
给一棵
n
n
n 个点的树,每条边可以断开,也可以不断开,求和
1
1
1 所在的连通块大小为
k
k
k 的方案数,
k
=
1
,
2
,
3
,
.
.
.
,
n
k=1,2,3,...,n
k=1,2,3,...,n。答案对
1811939329
1811939329
1811939329 取模。
n
≤
1
0
5
n\le 10^5
n≤105。
分析
令
F
u
[
x
n
]
F_u[x^n]
Fu[xn] 表示
u
u
u 向
f
a
u
fa_u
fau 贡献连通块大小为
n
n
n 的方案数。
因此有
F
u
=
F
u
[
x
0
]
+
x
∏
(
u
,
v
)
F
v
F_u=F_u[x^0]+x\prod\limits_{(u,v)}F_v
Fu=Fu[x0]+x(u,v)∏Fv。
其中,
F
u
[
x
0
]
=
2
s
z
u
−
1
F_{u}[x^0]=2^{sz_u-1}
Fu[x0]=2szu−1,表示
(
u
,
f
a
u
)
(u,fa_u)
(u,fau) 这条边断开,
u
u
u 的子树里的边随便断的方案数。
然后树剖,令
G
u
=
x
∏
(
u
,
v
)
,
v
≠
s
o
n
u
F
v
,
K
u
=
∏
(
u
,
v
)
,
v
≠
s
o
n
u
2
K
v
G_u=x\prod\limits_{(u,v),v\neq son_u}F_v,K_u=\prod\limits_{(u,v),v\neq son_u}2K_v
Gu=x(u,v),v=sonu∏Fv,Ku=(u,v),v=sonu∏2Kv,
G
u
G_u
Gu 可以用分治
n
t
t
ntt
ntt 在
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n) 内求出。
然后考虑一条重链的合并,有以下递推式:
[
F
u
H
u
]
=
[
G
u
G
u
0
2
K
u
]
[
F
s
o
n
u
H
s
o
n
u
]
\begin{bmatrix}F_u\\H_u\end{bmatrix}=\begin{bmatrix}G_u&G_u\\ 0 & 2K_u\end{bmatrix}\begin{bmatrix}F_{son_u}\\H_{son_u}\end{bmatrix}
[FuHu]=[Gu0Gu2Ku][FsonuHsonu]
H
u
H_u
Hu 即为
F
u
[
x
0
]
F_{u}[x^0]
Fu[x0]。
然后分治求矩阵乘积就可以了,这部分的复杂度也是
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n) 的。
写得好不详细啊=.=,建议不会的先去学一下树剖分治ntt。这是一道例题
代码如下。
#include <bits/stdc++.h>
#define all(x) x.begin(), x.end()
#define pii pair<int, int>
#define fi first
#define se second
#define sz(x) x.size()
using namespace std;
typedef long long ll;
void debug_out(){
cerr << endl;
}
template<typename Head, typename... Tail>
void debug_out(Head H, Tail... T){
cerr << " " << to_string(H);
debug_out(T...);
}
#ifdef local
#define debug(...) cerr<<"["<<#__VA_ARGS__<<"]:",debug_out(__VA_ARGS__)
#else
#define debug(...) 55
#endif
typedef unsigned int uint;
namespace Poly {
typedef vector<uint> poly;
constexpr uint Max_size = 1 << 21 | 5;
constexpr int gn = 13;
const int mod = 1811939329;
ll power(ll a, ll b) { ll res = 1; while (b) { if (b & 1)res = res * a % mod; a = a * a % mod; b >>= 1; }return res; }
inline uint mf(uint x)
{
return (static_cast<ll>(x) << 32) / mod;
}
int sz;
uint w[Max_size], w_mf[Max_size];
inline void init(int n)
{
for (sz = 2; sz < n; sz <<= 1);
uint pr = power(gn, (mod - 1) / sz);
w[sz / 2] = 1, w_mf[sz / 2] = mf(w[sz / 2]);
for (int i = 1; i < sz / 2; ++i)
w[sz / 2 + i] = (ll)w[sz / 2 + i - 1] * pr % mod, w_mf[sz / 2 + i] = mf(w[sz / 2 + i]);
for (int i = sz / 2 - 1; i; --i)
w[i] = w[i << 1], w_mf[i] = w_mf[i << 1];
}
inline void NTT(poly& A, const int L)
{
for (int d = L >> 1; d; d >>= 1)
for (int i = 0; i != L; i += d << 1)
for (int j = 0; j != d; ++j)
{
uint x = (A[i + j] + A[i + d + j])%mod;
ll t = (A[i + j] + mod - A[i + d + j]) % mod;
ll q = t * w_mf[d + j] >> 32;
uint y = (t * w[d + j] - q * mod)%mod;
A[i + j] = x, A[i + d + j] = y;
}
}
inline void INTT(poly& A, const int L)
{
for (int d = 1; d != L; d <<= 1)
for (int i = 0; i != L; i += d << 1)
for (int j = 0; j != d; ++j)
{
ll x = A[i + j];
ll y = A[i + d + j];
ll q = y * w_mf[d + j] >> 32;
ll t = y * w[d + j] - q * mod;
A[i + j] = (x + t)%mod, A[i + d + j] = (x + mod - t % mod) % mod;
}
reverse(A.begin() + 1, A.end());
int k = __builtin_ctz(L);
for (int i = 0; i != L; ++i)
{
ll m = -A[i] & (L - 1);
A[i] = (A[i] + m * mod) >> k;
}
}
poly operator*(poly a, poly b) {
int n = a.size() + b.size() - 1, R = 2;
if (n <= 0)return {};
for (; R <= n; R <<= 1); init(R);
a.resize(R), b.resize(R);
NTT(a, R); NTT(b, R);
for(int i = 0; i < R; i++) a[i] = 1ll * b[i] * a[i] % mod;
INTT(a, R); a.resize(n);
for(int i = 0; i < n; i++) if (a[i] >= mod)a[i] -= mod;
return a;
}
poly operator*(uint a, poly b) {
for (auto& I : b)I = (ll)I * a % mod;
return b;
}
poly operator+(poly a, poly b) {
int n = max(a.size(), b.size());
a.resize(n), b.resize(n);
for(int i = 0; i < n; i++) a[i] = (a[i]+b[i])%mod;
return a;
}
poly operator-(poly a, poly b) {
int n = max(a.size(), b.size());
a.resize(n), b.resize(n);
for(int i = 0; i < n; i++)a[i] = (a[i] + mod - b[i])%mod;
return a;
}
}; using namespace Poly;
const int N = 2e5 + 5;
vector<int> E[N];
int siz[N], Fa[N], son[N], dfn[N], top[N], dft;
void dfs1(int u, int pre){
siz[u] = 1;
for(int& v: E[u]){
if(v == pre) continue;
dfs1(v, u);
Fa[v] = u;
siz[u] += siz[v];
if(siz[v] >= siz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int f){
top[u] = f, dfn[++dft] = u;
if(son[u]) dfs2(son[u], f);
for(int& v: E[u]) if(v != Fa[u] && v != son[u]) dfs2(v, v);
}
struct Chain{
poly f0, f1;
uint k;
};
Chain operator * (Chain a, Chain b){
Chain c;
c.f0 = a.f0 * b.f0;
c.f1 = a.f0 * b.f1 + b.k * a.f1;
c.k = (ll)a.k * b.k % mod;
return c;
}
poly merge(vector<poly>& g, int l, int r){
if(l == r) return g[l];
int m = l + r >> 1;
return merge(g, l, m) * merge(g, m + 1, r);
}
Chain merge(vector<Chain>& g, int l, int r){
if(l == r) return g[l];
int m = l + r >> 1;
Chain a = merge(g, l, m), b = merge(g, m + 1, r);
return a * b;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T--){
dft = 0;
int n;
cin >> n;
for(int i = 1, u, v; i < n; i++){
cin >> u >> v;
E[u].push_back(v);
E[v].push_back(u);
}
dfs1(1, 0);
dfs2(1, 1);
vector<poly> f(n + 1, {0, 1});
poly k(n + 1, 1);
for(int i = n; i >= 1; i--){
int x = dfn[i];
vector<Chain> chain;
if(x == top[x]){
for(int u = x; top[u] == x; u = son[u]){
vector<poly> g(1, f[u]);
for(int& v: E[u]){
if(v == son[u] || v == Fa[u]) continue;
f[v][0] = k[v];
k[u] = (ll)2 * k[u] * k[v] % mod;
g.push_back(f[v]);
}
poly tmp = merge(g, 0, g.size() - 1);
Chain res;
res.f0 = res.f1 = tmp;
res.k = k[u] * 2 % mod;
chain.push_back(res);
}
if(chain.size() > 1){
poly w = {0, 1};
Chain tmp = merge(chain, 0, chain.size() - 2);
f[x] = tmp.f0 * w + tmp.f1;
k[x] = tmp.k;
}
}
}
f[1].resize(n + 1);
for(int i = 1; i <= n; i++) cout << f[1][i] << (i == n? "\n": " ");
for(int i = 1; i <= n; i++) E[i].clear(), siz[i] = 0, Fa[i] = 0, son[i] = 0, top[i] = 0, dfn[i] = 0;
}
return 0;
}