题目链接:http://codeforces.com/problemset/problem/337/D
解题思路:显然我们要找到这样的点,使得这个点到所有污染点的最远距离小于K,某个节点到污染点最远距离是由此节点到这个节点子树中的污染点的最远距离和父节点到兄弟子树中污染点的最远距离+1取最大值得到的。我们要保留一个此节点到子树中的最远距离dis[i],此节点向上走的最远距离updis[i],此节点到子树中距离最远的前两个Max[i][2],然后第一遍dfs处理dis数组和Max数组,第二遍统计一下就行了,下面上代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int fa[N],dis[N],updis[N],head[N],Max[N][2];
int cnt,ans;
int n,m,k;
struct node
{
int v,next;
}edge[2*N];
int addedge(int a,int b)
{
edge[cnt].v = b;
edge[cnt].next = head[a];
head[a] = cnt++;
}
void dfs1(int u,int f)
{
fa[u] = f;
for(int i = head[u];i!=-1;i = edge[i].next)
{
int v = edge[i].v;
if(v == fa[u])continue;
dfs1(v,u);
int tmp = dis[v] == -1?-1:dis[v]+1;
if(tmp>Max[u][0])
{
dis[u] = tmp;
Max[u][1] = Max[u][0];
Max[u][0] = tmp;
}
else if(tmp>Max[u][1])
{
Max[u][1] = tmp;
}
}
}
void dfs2(int u)
{
updis[u] = max(updis[u],updis[fa[u]] == -1?-1:updis[fa[u]]+1);
int tmp = dis[u] == -1?-1:dis[u]+1;
if(Max[fa[u]][0]!=tmp)
{
updis[u] = max(updis[u],Max[fa[u]][0] == -1?-1:Max[fa[u]][0]+1);
}
else
{
updis[u] = max(updis[u],Max[fa[u]][1] == -1?-1:Max[fa[u]][1]+1);
}
if(max(dis[u],updis[u])<=k)ans++;
for(int i = head[u];i!=-1;i = edge[i].next)
{
int v = edge[i].v;
if(v == fa[u])continue;
dfs2(v);
}
}
int main()
{
int i,j,a,b;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
cnt = ans = 0;
memset(head,-1,sizeof(head));
memset(dis,-1,sizeof(dis));
memset(updis,-1,sizeof(updis));
memset(Max,-1,sizeof(Max));
for(i = 1;i<=m;i++)
{
scanf("%d",&a);
Max[a][0] = Max[a][1] = dis[a] = updis[a] = 0;
}
for(i = 1;i<n;i++)
{
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
fa[0] = fa[1] = 0;
dfs1(1,0);
dfs2(1);
printf("%d\n",ans);
}
return 0;
}