感受
我真菜,居然做不出来
什么时候我可以变得强起来!
思路
看完题解后,恍然大悟。
对于一个一定不能由子树覆盖的点,那么这个点一定要染色。
那么染色一定是染这个点w吗?不是,其实可以染子树中的任意一点,只需要保证染完之后,假设染的是u,那么从u到w后的向上延伸距离最大(k[u] - (dep[u] - dep[w]).
题解在处理这个子问题时比我的想法简单不少,可以一直更新每一个节点的最大延伸距离,然后从而达到这个效果。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 10; struct edge{ int v, nex; }e[maxn * 2]; int head[maxn], cnt, n; int dp[maxn], k[maxn];///dp[i]表示i节点往上还可以最多走几步(走到的位置为必须染色时刻) ///k[i]表示以i为当前根的子树所有节点到达i后还可以往上走步数的最大值 void add_edge(int u, int v){ cnt++; e[cnt] = (edge){v, head[u]}; head[u] = cnt; } int ans; void dfs(int u, int f){ int v; for(int i = head[u]; i > 0; i = e[i].nex){ v = e[i].v; if(v == f) continue; dfs(v, u); dp[u] = max(dp[u], dp[v] - 1); k[u] = max(k[u], k[v] - 1); } if(!dp[u]){ ans++; dp[u] = k[u]; } } int main(){ scanf("%d", &n); int fa; for(int i = 2; i <= n; i++){ scanf("%d", &fa); add_edge(i, fa); add_edge(fa, i); } for(int i = 1; i <= n; i++){scanf("%d", &k[i]);} dfs(1, 0); printf("%d\n", ans); return 0; }