最大独立集 ccpcwannnafly (贪心最大独立集)


题目描述

 

树上最大独立集是个非常简单的问题,可怜想让它变得稍微难一点。

可怜最开始有一棵 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}Ti1 一样的有根树,并将第 jj 棵树的根节点的父亲设置为 T_bTb 中第 jj 个点,即加上一条连接它们的边。
  • 这样就得到了一个点数为 \text{size}(T(k_i)) + n\times \text{size}(T'_{i-1})size(T(ki))+n×size(Ti1) 的树 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(1n,m105),表示无根树上的节点个数与可怜进行的操作次数。

接下来 n-1n1 行每行两个整数 u,v(1 \leq u,v \leq n)u,v(1u,vn) 表示书上的一条边。

接下来 mm 行每行一个整数 k_i(1 \leq k_i \leq n)ki(1kin) 表示在第 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]ig[i]表示不考虑i的子树当前点取不取

显然,g[1]=1g[1]=1表示根节点不考虑其子树是取的

再考虑其他点uug[fa[u]]=1u,如果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 }

 
















免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM