Book of Evil
又是一道虚高的紫题。
题意是说给定一棵树,树上一些点为特殊点,求到所有特殊点的距离均不超过给定值的点的个数。
换根的板子。对于每个点维护在子树内离自己最远的特殊点和第二远的特殊点,用 \(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;
}
一如既往,万事胜意