题目描述
树上最大独立集是个非常简单的问题,可怜想让它变得稍微难一点。
可怜最开始有一棵 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 个点,即加上一条连接它们的边。
- 这样就得到了一个点数为 \text{size}(T(k_i)) + n\times \text{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\n", 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\n", res); 68 } 69 return 0; 70 }