Codeforces Round #196 (Div. 1) B. Book of Evil 树形DP
链接:
http://codeforces.com/contest/338/problem/B
题意:
给出一棵树,给出感染物的感染范围,给出一些已经确定被感染的点,问感染物可能放置的点的个数。
题解:
定义状态dp[i]代表某个点到达离它最远的确定的感染点的距离。
然后我们首先dfs一遍,求得以1为根的树,每个点到子树中的感染点的最大距离,然后再dfs一遍,求得dp[i]所要求的值,利用一个dd[i]数组表示第i点的父亲,除了自己及以自己为根的子树的点的感染点到自己的最远距离。
然后处理出来每个点儿子的前缀和后缀的最大值,然后利用dd就可以求取dp[i]
代码:
31 int n, m, d; 32 int p[MAXN]; 33 VI G[MAXN]; 34 int dp[MAXN], dd[MAXN]; 35 int lef[MAXN], rig[MAXN]; 36 37 void dfs(int u, int par) { 38 if (p[u]) dp[u] = 0; 39 rep(i, 0, G[u].size()) { 40 int v = G[u][i]; 41 if (v == par) continue; 42 dfs(v, u); 43 dp[u] = max(dp[u], dp[v] + 1); 44 } 45 } 46 47 void dfs1(int u, int par) { 48 lef[0] = -INF; 49 rig[G[u].size() + 1] = -INF; 50 rep(i, 0, G[u].size()) { 51 int x = i + 1; 52 int v = G[u][i]; 53 if (v == par) { 54 lef[x] = lef[x - 1]; 55 continue; 56 } 57 lef[x] = max(lef[x - 1], dp[v]); 58 } 59 per(i, 0, G[u].size()) { 60 int x = i + 1; 61 int v = G[u][i]; 62 if (v == par) { 63 rig[x] = rig[x + 1]; 64 continue; 65 } 66 rig[x] = max(rig[x + 1], dp[v]); 67 } 68 rep(i, 0, G[u].size()) { 69 int x = i + 1; 70 int v = G[u][i]; 71 if (v == par) continue; 72 dd[v] = max(dd[u], max(lef[x - 1], rig[x + 1]) + 1) + 1; 73 dp[v] = max(dp[v], dd[v]); 74 } 75 rep(i, 0, G[u].size()) { 76 int v = G[u][i]; 77 if (v == par) continue; 78 dfs1(v, u); 79 } 80 } 81 82 int main() { 83 ios::sync_with_stdio(false), cin.tie(0); 84 cin >> n >> m >> d; 85 rep(i, 0, m) { 86 int x; 87 cin >> x; 88 p[x] = 1; 89 } 90 rep(i, 1, n) { 91 int u, v; 92 cin >> u >> v; 93 G[u].pb(v); 94 G[v].pb(u); 95 } 96 memset(dp, -0x3f, sizeof(dp)); 97 memset(dd, -0x3f, sizeof(dd)); 98 dfs(1, -1); 99 if (p[1]) dd[1] = 0; 100 dfs1(1, -1); 101 int ans = 0; 102 rep(i, 1, n + 1) if (dp[i] >= 0 && dp[i] <= d) ans++; 103 cout << ans << endl; 104 return 0; 105 }