題目描述
樹上最大獨立集是個非常簡單的問題,可憐想讓它變得稍微難一點。
可憐最開始有一棵 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 }
