CF 337D Book of Evil 树形DP 好题

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 31 21 52 33 44 55 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 }

时间: 2024-10-14 23:16:40

CF 337D Book of Evil 树形DP 好题的相关文章

POJ 1155 TELE 背包型树形DP 经典题

由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送数据到达另一个节点,电视台需要一定的费用 若可以传送数据到达用户的节点n-m+1~n,这些用户各自愿意支付一定的费用给电视台 现在电视台希望在不亏本的情况下为尽量多的用户转播比赛 输出最多可以为多少用户转播比赛 背包类型的树形DP第一题 dp[i][j]表示以节点i为根的子树有j个用户获得转播,电视

URAL 1039 Anniversary Party 树形DP 水题

1039. Anniversary Party Time limit: 0.5 secondMemory limit: 8 MB Background The president of the Ural State University is going to make an 80'th Anniversary party. The university has a hierarchical structure of employees; that is, the supervisor rela

树形DP经典题

题目传送门 题意: 给出一棵树,求离每个节点最远的点的距离 思路: 把无根树转化成有根树分析, 对于上面那棵树,要求距结点2的最长距离,那么,就需要知道以2为顶点的子树(蓝色圈起的部分,我们叫它Tree(2)),距顶点2的最远距离L1 还有知道2的父节点1为根节点的树Tree(1)-Tree(2)部分(即红色圈起部分),距离结点1的最长距离+dist(1,2) = L2,那么最终距离结点2最远的距离就是max{L1,L2} f[i][0],表示顶点为i的子树的,距顶点i的最长距离 f[i][1]

POJ 3342 树形DP入门题

题目意思和POJ2342一样,只是多加了一个条件,如果最大方案数唯一,输出Yes,不唯一输出No dp的是时候多加一个变量记录答案是否唯一即可 #include "stdio.h" #include "string.h" #include "vector" using namespace std; struct node { int fa; vector<int>child; }data[210]; struct comp { int

POJ 1947 树形DP入门题

给出N个点,N-1个关系,建出树形图,问最少减去几个边能得到节点数为P的树.典型树形DP题 dp[cur][j] :记录cur结点,要得到一棵j个节点的子树去掉的最少边数 转移方程用的背包的思想 对当前树的每一个子树进行计算 砍掉此子树:   dp[cur][j]=dp[cur][j]+1; 不砍掉:           for (l=0;l<=j;l++)  dp[cur][j]=Min(dp[cur][j],dp[cur][l]+dp[next][j-l]); 枚举从该树中留l个节点其他由新

POJ 2342 树形DP入门题

有一个大学的庆典晚会,想邀请一些在大学任职的人来参加,每个人有自己的搞笑值,但是现在遇到一个问题就是如果两个人之间有直接的上下级关系,那么他们中只能有一个来参加,求请来一部分人之后,搞笑值的最大是多少. 树形DP入门题. DP部分: dp[i][0]表示职员i不来参加party,以i为根的子树的最大搞笑值, dp[i][1]表示职员i来参加party,以i为根的子树的最大搞笑值. 转移方程: dp[cur][1]+=dp[next][0]; dp[cur][0]+=Max(dp[next][1]

URAL 1018 Binary Apple Tree 树形DP 好题 经典

1018. Binary Apple Tree Time limit: 1.0 secondMemory limit: 64 MB Let's imagine how apple tree looks in binary computer world. You're right, it looks just like a binary tree, i.e. any biparous branch splits up to exactly two new branches. We will enu

P2016 战略游戏——树形DP大水题

P2016 战略游戏 树形DP 入门题吧(现在怎么是蓝色标签搞不懂): 注意是看见每一条边而不是每一个点(因为这里错了好几次): #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=3010; int pre[maxn],last[maxn],other[maxn],l; void add(int x,int y) { l++; pre[l]

CF EDU 1101D GCD Counting 树形DP + 质因子分解

CF EDU 1101D GCD Counting 题意 有一颗树,每个节点有一个值,问树上最长链的长度,要求链上的每个节点的GCD值大于1. 思路 由于每个数的质因子很少,题目的数据200000<2*3*5*7*11*13*17=510510.所以每个节点的质因子个数不多.那么树形DP的时候直接枚举每种因子即可. //#pragma GCC optimize(3) //#pragma comment(linker, "/STACK:102400000,102400000") /