Book of Evil

link

又是一道虚高的紫题。

题意是说给定一棵树,树上一些点为特殊点,求到所有特殊点的距离均不超过给定值的点的个数。

换根的板子。对于每个点维护在子树内离自己最远的特殊点和第二远的特殊点,用 \(O(N)\) 的时间求出根节点的信息;然后二次换根,每个节点考虑父亲的最远点是否来自自己的子树,如果是就取父亲的次远节点,否则取最远节点即可。这一部分也是 \(O(N)\) 的。

代码仍然异常简洁。

#include<bits/stdc++.h>
//#define zczc
const int N=100010;
using namespace std;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline int max(int s1,int s2){
	return s1<s2?s2:s1;
}

int m,n,d,s1,s2,d1[N],d2[N];
struct edge{
	int t,next;
}e[N<<1];
int head[N],esum;
inline void add(int fr,int to){
	e[++esum]=(edge){to,head[fr]};head[fr]=esum;
}
bool a[N];

void solve1(int wh,int fa){
	if(a[wh])d1[wh]=0;
	for(int i=head[wh],th;i;i=e[i].next){
		if((th=e[i].t)==fa)continue;
		solve1(th,wh);
		if(d1[th]+1>d1[wh])d2[wh]=d1[wh],d1[wh]=d1[th]+1;
		else d2[wh]=max(d2[wh],d1[th]+1);
	}
}
void solve2(int wh,int fa){
	if(wh!=1){
		int dis=d1[wh]+1==d1[fa]?d2[fa]+1:d1[fa]+1;
		if(dis>d1[wh])d2[wh]=d1[wh],d1[wh]=dis;
		else d2[wh]=max(d2[wh],dis);
	}
	for(int i=head[wh],th;i;i=e[i].next){
		if((th=e[i].t)==fa)continue;
		solve2(th,wh);
	}
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);read(d);
	for(int i=1;i<=n;i++){
		read(s1);a[s1]=true;
	}
	for(int i=1;i<m;i++){
		read(s1);read(s2);
		add(s1,s2);add(s2,s1);
	}
	memset(d1,0xcf,sizeof(d1));
	memset(d2,0xcf,sizeof(d2));
	solve1(1,0);
	
	//for(int i=1;i<=m;i++)printf("%d %d\n",d1[i],d2[i]);
	
	solve2(1,0);
	int ans=0;
	for(int i=1;i<=m;i++)ans+=(d1[i]<=d);
	printf("%d",ans);
	
	return 0;
}
posted @ 2022-06-30 19:58  Feyn618  阅读(26)  评论(0编辑  收藏  举报