最大独立集 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 }














猜你喜欢

转载自www.cnblogs.com/zhangbuang/p/10956857.html