CF337D Book of Evil【dfs】

题意:有一棵树,树上有些特殊的点,问有几个点到这些的点距离都小于等于d


思路:知道这个就很简单了。如果一棵树T的直径上的两个端点分别是A, B ,且T是树S的一部分 ,那么如果S上某个点到A, B的距离不超过D,那么这个点到这棵子树上的所有点的距离不超过D。dfs两次找到两个端点,再从这两个点开始dfs求其他点距此的距离。最后遍历所有点


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair pii;
const int maxn = 1e5+5;

struct Edge
{
	int to,next;
}edge[maxn*2];
int head[maxn],tot;
int is[maxn],vis[maxn];
int st,en,deep,d1[maxn],d2[maxn];

void init()
{
	memset(head,-1,sizeof head);
	memset(is,0,sizeof is);
	tot = 0;
}

void add(int x,int y)
{
	edge[tot].to = y;
	edge[tot].next = head[x];
	head[x] = tot++;
}//for(int i = head[x]; i != -1; i = edge[i].next)

void dfs1(int x,int d)
{
	vis[x] = 1;
	if(is[x] && d > deep)
	{
		st = x;
		deep = d;
	}
	for(int i = head[x]; i != -1; i = edge[i].next)
	{
		int y = edge[i].to;
		if(vis[y]) continue;
		dfs1(y,d+1);
	}
}

void dfs2(int x,int d)
{
	vis[x] = 1;
	d1[x] = d;
	if(is[x] && d > deep)
	{
		en = x;
		deep = d;
	}
	for(int i = head[x]; i != -1; i = edge[i].next)
	{
		int y = edge[i].to;
		if(vis[y]) continue;
		dfs2(y,d+1);
	}
}

void dfs3(int x,int d)
{
	vis[x] = 1;
	d2[x] = d;
	for(int i = head[x]; i != -1; i = edge[i].next)
	{
		int y = edge[i].to;
		if(vis[y]) continue;
		dfs3(y,d+1);
	}
}

int main(void)
{
	int n,m,d;
	while(scanf("%d%d%d",&n,&m,&d)!=EOF)
	{
		init();
		for(int i = 0; i < m; i++)
		{
			int k;
			scanf("%d",&k);
			is[k] = 1;	
		}
		for(int i = 1; i < n; i++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			add(a,b);
			add(b,a);
		}
		deep = -1;
		memset(vis,0,sizeof vis);
		dfs1(1,0);
		
		deep = -1;
		memset(vis,0,sizeof vis);
		dfs2(st,0);
		
		memset(vis,0,sizeof vis);
		dfs3(en,0);
		int ans = 0;
		for(int i = 1; i <= n; i++)
		{
			if(d1[i] <= d && d2[i] <= d)
				ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}


你可能感兴趣的:(dfs)