题目
n(1<=n<=1e5)个点,
一个BUF发射点,会使得与其距离小于等于d的点都受到BUFF笼罩
现给出受到了BUFF笼罩的m(m<=n)个点,
以下n-1行输入双向边代表一棵树,
问哪些点可能是BUFF发射点
思路来源
https://blog.csdn.net/u013912596/article/details/38695009
题解
感觉树上最远两点这个还是不好想的,但题解可以看懂,
如果最远两点u,v求出来了,那么这两点之间距离不会超过2d
而且BUFF点和u和v都不会超过d,
且如果w与u的距离小于w与v的距离,说明w距BUFF点较v距BUFF点更近
这说明,只需统计到u和v距离不超过d的节点即可,思路转换
心得
树是可以理解成线性区间的.jpg
CF的题面真是又臭又长,不如改题面鸭……
树形dp还是不熟叭,还是要多写写鸭……
再就是培养CF思维吧,虽然在能力之内但总是写不出来
vector挺好用的,能不用链式前向星就不用
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=1e5+10;
vector<int>E[maxn];
bool ok[maxn];
int n,m,d;
int u,v,w;//两个距离最远的点
int dis1[maxn],dis2[maxn];
int ans,res;//最大深度 最终答案
void add2(int u,int v)
{
E[u].push_back(v);
E[v].push_back(u);
}
void dfs(int dis[],int u,int fa,int dep,int &res)
{
dis[u]=dep;
for(int i=0;i<E[u].size();++i)
{
int v=E[u][i];
if(v==fa)continue;
dfs(dis,v,u,dep+1,res);
}
if(dep>ans&&ok[u])//是被影响的点 还是最深的
{
ans=dep;
res=u;//最深节点
}
}
int main()
{
scanf("%d%d%d",&n,&m,&d);
for(int i=1;i<=m;++i)
{
scanf("%d",&u);
ok[u]=1;
}
for(int i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
add2(u,v);
}
ans=-1;//最大深度初始化
dfs(dis1,1,-1,0,u);//(距离数组,出发点,父节点,当前深度,距出发点最远的节点)
ans=-1;
dfs(dis1,u,-1,0,v);
ans=-1;
dfs(dis2,v,-1,0,w);
for(int i=1;i<=n;++i)
if(dis1[i]<=d&&dis2[i]<=d)res++;
printf("%d\n",res);
return 0;
}