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 }

 

posted @ 2017-08-10 14:17  Flowersea  阅读(176)  评论(0编辑  收藏  举报