Codeforces Round #196 (Div. 2) D.Book of Evil(树形dp)

题目

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;
} 

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/89158823