题解 CF1593E Gardener and Tree

智子

2021-10-15 00:06:28

Solution

## 题意 对一棵 $n$ 个节点的树进行 $k$ 次操作,每次操作删去当前树的所有叶结点,求 $k$ 次操作后树还剩下多少个节点。 ## 思路 注意到每个节点“在哪一次操作中被删去”的属性有明显的先后顺序,所以我们可以对这棵树进行一个拓扑排序。 定义每个节点“在哪一次操作中被删去”的值为 $rnk_i$。每次检查到 $deg_v = 1$ 的节点 $v$ 就将其入队,同时用“引荐”它入队的节点 $u$ 计算 $v$ 的 $rnk$ 值,$rnk_v = rnk_u + 1$。 最后检查哪些节点的 $rnk$ 值小于 $k$,这些节点会被剪掉,其他节点的数量就是答案。 ## 代码 ```cpp #include<iostream> #include<fstream> #include<algorithm> #include<vector> #include<queue> #include<cstring> using namespace std; const int MAXN = 400000 + 5; vector<int> G[MAXN]; int deg[MAXN], rnk[MAXN]; int n, k; void toposort() { queue<int> q; for(int i = 1; i <= n; i++) { if(deg[i] == 1) { q.push(i); rnk[i] = 1; } } while(!q.empty()) { int u = q.front(); q.pop(); for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(--deg[v] == 1) { rnk[v] = rnk[u] + 1; q.push(v); } } } } int main() { int T; cin >> T; while(T--) { memset(deg, 0, sizeof(deg)); memset(rnk, 0, sizeof(rnk)); cin >> n >> k; for(int i = 1; i <= n; i++) { G[i].clear(); } for(int i = 1; i <= n - 1; i++) { int u, v; cin >> u >> v; G[u].push_back(v); G[v].push_back(u); deg[u]++; deg[v]++; } toposort(); int ans = n; for(int i = 1; i <= n; i++) { if(rnk[i] <= k) { ans--; } } cout << ans << endl; } return 0; } ```