题目描述
树上最大独立集是个非常简单的问题,可怜想让它变得稍微难一点。
可怜最开始有一棵 nn 个点无根树 TT,令 T(i)T(i) 为将点 ii 作为根后得到的有根树。
可怜用 mm 次操作构造了 m+1m+1 棵树 T'_0T0′ 至 T'_mTm′,其中 T'_0 = T(1)T0′=T(1)。第 ii 次操作,可怜选择了一个节点 k_iki,它用如下的方式构造了 T'_iTi′:
- 新建一棵和 T(k_i)T(ki) 一样的有根树 T_bTb。
- 新建 nn 棵和 T'_{i-1}Ti−1′ 一样的有根树,并将第 jj 棵树的根节点的父亲设置为 T_bTb 中第 jj 个点,即加上一条连接它们的边。
- 这样就得到了一个点数为 ext{size}(T(k_i)) + n imes ext{size}(T'_{i-1})size(T(ki))+n×size(Ti−1′) 的树 T_iTi,它的根节点是 T_bTb 中的节点 k_iki。
现在可怜希望你对 T_0T0 至 T_mTm,分别求出这 m+1m+1 棵树的最大独立集大小。
有根树 TT 的独立集 SS 的定义是 :SS 是 TT 上节点的子集,同时对于任意 SS 中的点 ii,ii 的父亲 f_ifi 不在 SS 中。
输入描述
第一行输入两个整数 n,m(1 leq n,m leq 10^5)n,m(1≤n,m≤105),表示无根树上的节点个数与可怜进行的操作次数。
接下来 n-1n−1 行每行两个整数 u,v(1 leq u,v leq n)u,v(1≤u,v≤n) 表示书上的一条边。
接下来 mm 行每行一个整数 k_i(1 leq k_i leq n)ki(1≤ki≤n) 表示在第 ii 次操作中,可怜选择的节点。
输出描述
输出 m+1m+1 行,每行一个整数,表示对应的树的最大独立集的大小。答案可能很大, 对 998244353998244353 取模后输出。
样例输入 1
1 5
1
1
1
1
1
样例输出 1
1
1
2
2
3
3
样例输入 2
5 5
1 2
2 3
2 4
1 5
5
4
3
2
1
样例输出 2
3
18
93
465
2328
11643
基础是要会求树上独立集,一个是树形dp,太暴力了,并且这里的也用不上。
然年就是有一个贪心的做法,
就是每次取树的叶子, 删掉叶子的fa,一次类推
实现的话,一次dfs就行了。
然后
树上独立集的贪心做法:
每次取出叶子节点加入答案,然后将其父节点扔掉,循环操作,直至没有节点
那么考虑这一道题的操作,对于一棵树T(ki)来说T(ki)来说
它的每一个节点下面都连着一棵独立的树
那么这些独立的树都可以分别贪心求最大独立集
再考虑这些独立的树做完之后剩下的T(ki)T(ki)
如果这些独立的树的最大独立集需要取到其根节点,那么T(ki)中所有节点都不能取T(ki)中所有节点都不能取
否则T(ki)的贡献就是以ki为根的最大独立集T(ki)的贡献就是以ki为根的最大独立集
这时候需要预处理出以x∈[1,n]为根的最大独立集中是否需要用到xx∈[1,n]为根的最大独立集中是否需要用到x
树形dp
第一次dp ,f[i]表示只考虑i的子树当前点取不取f[i]表示只考虑i的子树当前点取不取
显然,对于所有叶子节点都是取的 ,f[i]=1f[i]=1
那么对于非叶子节点 f[i]=1当且仅当其所有儿子的f[i]=0f[i]=1当且仅当其所有儿子的f[i]=0
第二次dp g[i]表示不考虑i的子树当前点取不取g[i]表示不考虑i的子树当前点取不取
显然,g[1]=1表示根节点不考虑其子树是取的g[1]=1表示根节点不考虑其子树是取的
再考虑其他点u,如果u是不取的,当且仅当g[fa[u]]=1并且其父亲除它u,如果u是不取的,当且仅当g[fa[u]]=1并且其父亲除它
以外的儿子中的f[i]都是不取的
第二次dp g[i]表示不考虑i的子树当前点取不取g[i]表示不考虑i的子树当前点取不取
显然,g[1]=1表示根节点不考虑其子树是取的g[1]=1表示根节点不考虑其子树是取的
再考虑其他点u,如果u是不取的,当且仅当g[fa[u]]=1并且其父亲除它u,如果u是不取的,当且仅当g[fa[u]]=1并且其父亲除它
以外的儿子中的f[i]都是不取的
1 #include <bits/stdc++.h>
2 using namespace std;
3
4 #define ll long long
5 #define N 200010
6 const ll MOD = (ll)998244353;
7 int n, m; ll base;
8 vector <int> G[N];
9
10 int fa[N], cnt[N], need[N];
11 // 0 get > 0 not get for cnt
12 void DFS(int u)
13 {
14 cnt[u] = 0;
15 for (auto v : G[u]) if (v != fa[u])
16 {
17 fa[v] = u;
18 DFS(v);
19 if (cnt[v] == 0) ++cnt[u];
20 }
21 if (cnt[u] == 0) ++base;
22 }
23
24
25 // need 0 get 1 not get
26 void DFS2(int u)
27 {
28 if (u != 1)
29 {
30 if (need[fa[u]] == 0 && cnt[fa[u]] - (cnt[u] == 0) == 0) need[u] = 1;
31 else need[u] = 0;
32 }
33 for (auto v : G[u]) if (v != fa[u])
34 DFS2(v);
35 }
36
37 int main()
38 {
39 while (scanf("%d%d", &n, &m) != EOF)
40 {
41 base = 0;
42 for (int i = 1; i <= n; ++i) G[i].clear();
43 for (int i = 1, u, v; i < n; ++i)
44 {
45 scanf("%d%d", &u, &v);
46 G[u].push_back(v);
47 G[v].push_back(u);
48 }
49 DFS(1);
50 need[1] = 0;
51 DFS2(1);
52 for (int i = 1; i <= n; ++i)
53 {
54 if (cnt[i] == 0 && need[i] == 0) need[i] = 1;
55 else need[i] = 0;
56 }
57 ll res = base;
58 int vis = need[1];
59 for (int i = 1, x; i <= m; ++i)
60 {
61 scanf("%d", &x);
62 printf("%lld
", res);
63 res = (res * n) % MOD;
64 if (vis == 0) res = (res + base) % MOD, vis = need[x];
65 else vis = 0;
66 }
67 printf("%lld
", res);
68 }
69 return 0;
70 }