码迷,mamicode.com
首页 > 其他好文 > 详细

CF 337D Book of Evil 树形DP 好题

时间:2015-08-31 00:43:41      阅读:527      评论:0      收藏:0      [点我收藏+]

标签:

Paladin Manao caught the trail of the ancient Book of Evil in a swampy area. This area contains n settlements numbered from 1 to n. Moving through the swamp is very difficult, so people tramped exactly n - 1 paths. Each of these paths connects some pair of settlements and is bidirectional. Moreover, it is possible to reach any settlement from any other one by traversing one or several paths.

The distance between two settlements is the minimum number of paths that have to be crossed to get from one settlement to the other one. Manao knows that the Book of Evil has got a damage range d. This means that if the Book of Evil is located in some settlement, its damage (for example, emergence of ghosts and werewolves) affects other settlements at distance d or less from the settlement where the Book resides.

Manao has heard of m settlements affected by the Book of Evil. Their numbers are p1, p2, ..., pm. Note that the Book may be affecting other settlements as well, but this has not been detected yet. Manao wants to determine which settlements may contain the Book. Help him with this difficult task.

Input

The first line contains three space-separated integers nm and d (1 ≤ m ≤ n ≤ 100000; 0 ≤ d ≤ n - 1). The second line contains m distinct space-separated integers p1, p2, ..., pm (1 ≤ pi ≤ n). Then n - 1 lines follow, each line describes a path made in the area. A path is described by a pair of space-separated integers ai and bi representing the ends of this path.

Output

Print a single number — the number of settlements that may contain the Book of Evil. It is possible that Manao received some controversial information and there is no settlement that may contain the Book. In such case, print 0.

Sample test(s)
input
6 2 3
1 2
1 5
2 3
3 4
4 5
5 6
output
3
Note

Sample 1. The damage range of the Book of Evil equals 3 and its effects have been noticed in settlements 1 and 2. Thus, it can be in settlements 3, 4 or 5.

 

 

 

 

题意:

1棵树,n个节点,编号为1~n,树的边权都是1再

给出m,d,然后有m个数

已知在某一个节点上有一个武器,与这个武器距离在d以内的节点都会受到辐射

现在已经知道有m个节点受到了辐射,问武器可能在的节点的个数

即求:这棵树上到这m个节点的距离都<=d的节点的个数。

 

树形DP,开始不知道怎么DP,总想着暴力。

 

令tree(i)表示以节点i为根的子树

把这m个节点称之为辐射点

dp[i][1] 表示tree(i)中,与i距离最远的辐射点的距离

dp[i][2] 表示tree(i)中,与i距离第二远的辐射点的距离(求dp[i][0]的时候需要用到)

dp[i][0] 表示整棵树-tree(i)中,与i距离最远的辐射点的距离

则与i距离最远的辐射点的距离=max(dp[i][1],dp[i][0])

若max(dp[i][0],dp[i][1])<=d,则节点i可能是武器的位置

则要求的就是满足max(dp[i][1],dp[i][0])<=d的i的个数

siz[i] 表示tree(i)中,辐射点的个数

son[i] 表示tree(i)中,dp[i][1]经过i的儿子节点son[i]

use[i] 表示节点i是不是辐射点

3次dfs,分别求出dp[i][1],dp[i][2],dp[i][0]

统计个数

 

 

 

技术分享
  1 #include<cstdio>
  2 #include<cstring>
  3 
  4 using namespace std;
  5 
  6 const int maxn=1e5+10;
  7 const int inf=0x3f3f3f3f;
  8 
  9 inline int max(int a,int b)
 10 {
 11     return a>b?a:b;
 12 }
 13 
 14 int dp[maxn][3];
 15 int siz[maxn];
 16 bool use[maxn];
 17 int son[maxn];
 18 struct Edge
 19 {
 20     int to,next;
 21 };
 22 Edge edge[maxn<<1];
 23 int head[maxn];
 24 int tot=0;
 25 
 26 void addedge(int u,int v)
 27 {
 28     edge[tot].to=v;
 29     edge[tot].next=head[u];
 30     head[u]=tot++;
 31 }
 32 
 33 void solve(int ,int ,int );
 34 void dfs0(int ,int );
 35 void dfs1(int ,int );
 36 void dfs2(int ,int ,int );
 37 
 38 int main()
 39 {
 40     memset(head,-1,sizeof head);
 41     memset(use,false,sizeof use);
 42     memset(son,-1,sizeof son);
 43     int n,m,d;
 44     scanf("%d %d %d",&n,&m,&d);
 45     for(int i=1;i<=m;i++){
 46         int u;
 47         scanf("%d",&u);
 48         use[u]=true;
 49     }
 50 
 51     for(int i=1;i<n;i++){
 52         int u,v;
 53         scanf("%d %d",&u,&v);
 54         addedge(u,v);
 55         addedge(v,u);
 56     }
 57     solve(n,m,d);
 58     return 0;
 59 }
 60 
 61 void solve(int n,int m,int d)
 62 {
 63     memset(dp,0,sizeof dp);
 64     dfs0(1,-1);
 65     dfs1(1,-1);
 66     dfs2(1,-1,m);
 67 
 68     int ans=0;
 69     for(int i=1;i<=n;i++){
 70         if(max(dp[i][0],dp[i][1])<=d)
 71             ans++;
 72     }
 73     printf("%d\n",ans);
 74     return ;
 75 }
 76 
 77 void dfs0(int u,int pre)
 78 {
 79     if(use[u])
 80         siz[u]=1;
 81     else
 82         siz[u]=0;
 83     for(int i=head[u];~i;i=edge[i].next){
 84         int v=edge[i].to;
 85         if(v==pre)
 86             continue;
 87         dfs0(v,u);
 88         if(siz[v]){
 89             dp[u][1]=max(dp[u][1],dp[v][1]+1);
 90             siz[u]+=siz[v];
 91             if(son[u]==-1||dp[v][1]>dp[son[u]][1])
 92                 son[u]=v;
 93         }
 94     }
 95 }
 96 
 97 void dfs1(int u,int pre)
 98 {
 99     for(int i=head[u];~i;i=edge[i].next){
100         int v=edge[i].to;
101         if(v==pre)
102             continue;
103         if(siz[v]){
104             dfs1(v,u);
105             if(v==son[u]){
106                 continue;
107             }
108             else{
109                 dp[u][2]=max(dp[u][2],dp[v][1]+1);
110             }
111         }
112     }
113 }
114 
115 void dfs2(int u,int pre,int m)
116 {
117     for(int i=head[u];~i;i=edge[i].next){
118         int v=edge[i].to;
119         if(v==pre)
120             continue;
121         if(m>siz[v]){
122             if(v==son[u])
123                 dp[v][0]=max(dp[u][0],dp[u][2])+1;
124             else
125                 dp[v][0]=max(dp[u][0],dp[u][1])+1;
126         }
127         dfs2(v,u,m);
128     }
129 }
View Code

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CF 337D Book of Evil 树形DP 好题

标签:

原文地址:http://www.cnblogs.com/-maybe/p/4771897.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!