-
容易想到一种暴力 DP:先转化成对于每个 (k) 求出 (max_{iin S}|i-w_i|le k) 的方案数,最后差分
-
然后问题转化成每个叶子的权值有个取值区间,注意这时我们可以把每个点的权值分成 (<W,=W,>W)(看作 (0,1,2) )三类处理,然后 DP (f[u][0/1/2])
-
然后你会很快发现这么做不行,因为选取某些叶子集合时,根节点的权值可以小于 (W) 也可以大于 (W) ,直接用 (2^m-1) 减掉 (f[u][0]+f[u][2]) 无法得到正确结果
-
于是我们尝试考虑怎样才能在 (<W) 和 (>W) 这两个条件中去掉一个
-
考虑权值为 (W) 的叶子到根的一条链
-
容易发现根节点的权值会被改变,当且仅当这条链上存在一个点会被改变
-
设这条链上有一个深度为奇数的点 (u) (偶数同理),考虑把链上所有的边都删掉之后 (u) 所在的连通块
-
易得在原树上 (u) 的权值会被改,当且仅当删边之后就 (u) 所在的连通块,能让 (u) 的权值大于 (W)
-
特殊地,如果 (u) 是叶子那么 (u) 的权值会被改当且仅当 (u) 在选定集合内且 (k>0)
-
这样我们就实现了在 (<W) 和 (>W) 这两个条件中去掉一个
-
我们有了一个 DP:(f[u]) 表示 (u) 的子树内的叶子节点有多少个子集能让 (u) 的权值大于 (W)
-
如果 (u) 的深度为奇数((cnt_u) 为 (u) 的子树内叶子个数):
-
[f[u]=2^{cnt_u}-prod_{vin son[u]}(2^{cnt_v}-f[v]) ]
-
否则:
-
[f[u]=prod_{vin son[u]}f[v] ]
-
把所有连通块的 DP 结果用 (2^{cnt}) 减掉后乘起来,即为根节点权值不会被改变的方案数
-
对每个 (k) 进行 DP 的复杂度为 (O(n^2))
-
考虑如何优化。我们注意到这个 DP 的转移和 (k) 无关,只有初始值(叶子)和 (k) 有关
-
而如果一个点 (u) 所在的连通块根在原树中的深度为奇数,那么点 (u) 的初值应该为:
-
[f[u]=[u>W]+[u+k>W] ]
-
注意到当 (k) 不断加一的时候, ([u+k>W]) 只会改变一次
-
于是从小到大枚举 (k) 后动态 DP 即可
-
注意由于 (f[u]) 可以为 (0) ,所以往上更新 DP 值时不能把 (f[fa[u]]) 直接除以 (f[u]) ,而需要对每个点维护一个变量表示子节点的 DP 值中有多少个 (0) ,另一个变量表示子节点不为 (0) 的 DP 值之积
-
(O(nlog^2n))
Code
#include <bits/stdc++.h>
#define p2 p << 1
#define p3 p << 1 | 1
template <class T>
inline void read(T &res)
{
res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
if (bo) res = ~res + 1;
}
template <class T>
inline T Min(const T &a, const T &b) {return a < b ? a : b;}
template <class T>
inline T Max(const T &a, const T &b) {return a > b ? a : b;}
const int N = 2e5 + 5, M = N << 1, L = M << 1, rqy = 998244353;
int n, l, r, dep[N], ecnt, nxt[M], adj[N], go[M], val[N], ans[N], f[N], cnt[N],
fa[N], sze[N], son[N], top[N], pos[N], idx[N], bot[N], QAQ, pw[N], re[N], c0[N],
rea = 1, cnt0;
bool lea[N], bel[N];
int qpow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) res = 1ll * res * a % rqy;
a = 1ll * a * a % rqy;
b >>= 1;
}
return res;
}
struct modi
{
int a, b;
friend inline modi operator * (modi x, modi y)
{
return (modi) {(int) (1ll * x.a * y.a % rqy),
(int) ((1ll * x.a * y.b + x.b) % rqy)};
}
friend inline int operator * (modi x, int y)
{
return (1ll * x.a * y + x.b) % rqy;
}
} g[N], gp[L];
void add_edge(int u, int v)
{
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}
void dfs(int u, int fu)
{
dep[u] = dep[fu] + 1;
val[u] = dep[u] & 1 ? 1 : n;
bool is = 1;
for (int e = adj[u], v; e; e = nxt[e])
if ((v = go[e]) != fu)
{
dfs(v, u); is = 0;
if (dep[u] & 1) val[u] = Max(val[u], val[v]);
else val[u] = Min(val[u], val[v]);
}
if (is) lea[val[u] = u] = 1, ans[0] = (ans[0] + ans[0]) % rqy;
}
void dfs1(int u, int fu, bool op)
{
fa[u] = fu; sze[u] = 1; bel[u] = op; cnt[u] = lea[u];
for (int e = adj[u], v; e; e = nxt[e])
if ((v = go[e]) != fu && val[v] != val[1])
{
dfs1(v, u, op);
sze[u] += sze[v]; cnt[u] += cnt[v];
if (sze[v] > sze[son[u]]) son[u] = v;
}
f[u] = (op ? val[u] > val[1] : val[u] < val[1]) ? pw[cnt[u]] : 0;
g[u].a = re[u] = 1;
if ((dep[u] & 1) ^ op)
{
for (int e = adj[u], v; e; e = nxt[e])
if ((v = go[e]) != fu && val[v] != val[1] && v != son[u])
{
g[u].a = 1ll * g[u].a * f[v] % rqy;
if (f[v]) re[u] = 1ll * re[u] * f[v] % rqy; else c0[u]++;
}
}
else
{
for (int e = adj[u], v; e; e = nxt[e])
if ((v = go[e]) != fu && val[v] != val[1] && v != son[u])
{
int tmp = (pw[cnt[v]] - f[v] + rqy) % rqy;
g[u].a = 1ll * g[u].a * tmp % rqy;
if (tmp) re[u] = 1ll * re[u] * tmp % rqy; else c0[u]++;
}
g[u].b = (pw[cnt[u]] - 1ll * g[u].a * pw[cnt[son[u]]] % rqy + rqy) % rqy;
}
bot[u] = son[u] ? bot[son[u]] : u;
}
void dfs2(int u, int fu)
{
if (son[u])
{
top[son[u]] = top[u];
idx[pos[son[u]] = ++QAQ] = son[u];
dfs2(son[u], u);
}
for (int e = adj[u], v; e; e = nxt[e])
if ((v = go[e]) != fu && v != son[u] && val[v] != val[1])
top[v] = v, idx[pos[v] = ++QAQ] = v, dfs2(v, u);
}
void build(int l, int r, int p)
{
if (l == r) return (void) (gp[p] = g[idx[l]]);
int mid = l + r >> 1;
build(l, mid, p2); build(mid + 1, r, p3);
gp[p] = gp[p2] * gp[p3];
}
void change(int l, int r, int pos, modi v, int p)
{
if (l == r) return (void) (gp[p] = v);
int mid = l + r >> 1;
if (pos <= mid) change(l, mid, pos, v, p2);
else change(mid + 1, r, pos, v, p3);
gp[p] = gp[p2] * gp[p3];
}
modi ask(int l, int r, int s, int e, int p)
{
if (e < l || s > r) return (modi) {1, 0};
if (s <= l && r <= e) return gp[p];
int mid = l + r >> 1;
return ask(l, mid, s, e, p2) * ask(mid + 1, r, s, e, p3);
}
void modify(int u, int x)
{
bool fi = 1; int of;
while (1)
{
int v = top[u], w = fa[v], rf = f[v], nf;
if (fi) fi = 0, f[u] = x; nf = f[v];
if (v != bot[u]) nf = f[v] =
ask(1, n, pos[v], pos[bot[u]] - 1, 1) * f[bot[u]] % rqy;
if (!w) {of = rf; u = v; break;}
if ((dep[v] & 1) ^ bel[v]) rf = (pw[cnt[v]] - rf + rqy) % rqy,
nf = (pw[cnt[v]] - nf + rqy) % rqy;
if (!rf) c0[w]--; else re[w] = 1ll * re[w] * qpow(rf, rqy - 2) % rqy;
if (!nf) c0[w]++; else re[w] = 1ll * re[w] * nf % rqy;
g[w].a = c0[w] ? 0 : re[w];
g[w].b = (dep[w] & 1) ^ bel[w] ? 0 : (pw[cnt[w]] -
1ll * g[w].a * pw[cnt[son[w]]] % rqy + rqy) % rqy;
change(1, n, pos[w], g[w], 1);
u = w;
}
if (of == pw[cnt[u]]) cnt0--; else rea = 1ll * rea *
qpow(pw[cnt[u]] - of + rqy, rqy - 2) % rqy;
if (f[u] == pw[cnt[u]]) cnt0++;
else rea = 1ll * rea * (pw[cnt[u]] - f[u] + rqy) % rqy;
}
int main()
{
int x, y;
read(n); read(l); read(r);
for (int i = 1; i < n; i++)
read(x), read(y), add_edge(x, y);
ans[0] = pw[0] = ans[n] = 1; dfs(1, 0);
for (int i = 1; i <= n; i++) pw[i] = (pw[i - 1] + pw[i - 1]) % rqy;
rea = 499122177ll * ans[0] % rqy;
for (int u = 1; u <= n; u++)
{
if (val[u] != val[1] || u == val[1]) continue;
dfs1(u, 0, dep[u] & 1);
if (!cnt[u] || lea[u]) continue;
idx[pos[u] = ++QAQ] = top[u] = u;
dfs2(u, 0);
}
build(1, n, 1);
for (int i = 1; i < n; i++)
{
if (i > 1 && val[1] >= i && lea[val[1] - i + 1] && bel[val[1] - i + 1])
modify(val[1] - i + 1, 1);
if (i > 1 && val[1] <= n - i + 1 && lea[val[1] + i - 1]
&& !bel[val[1] + i - 1]) modify(val[1] + i - 1, 1);
ans[i] = cnt0 ? 0 : rea;
}
for (int i = l; i <= r; i++) printf("%d ", (ans[i - 1] - ans[i] + rqy) % rqy);
return puts(""), 0;
}