分析

我们发现一个点是否可以作为魔法书的点
当且仅当距离他最近的点的距离
所以我们可以像求树的直径一样DP
求得每个点向下的距离最大值和距离次大值以及向上的距离最大值
最后在求完之后,统计一下有多少个点满足

即可
时间复杂度:
期望得分:100分

代码

//CF337D
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

#define LL long long
#define Cl(X,Y) memset((X),(Y),sizeof(X))
#define FOR(i,A,B) for(int i=A;i<=B;i++)
#define BOR(i,A,B) for(int i=A;i>=B;i--)
#define Lowbit(X) (X & (-X))
#define Skip cout<<endl;
#define INF 0x3f3f3f3f
#define Mod 998244353
#define Rson (X<<1|1)
#define Lson (X<<1)
using namespace std;
const int MaxN=1e5+10;

int Down_one[MaxN],Up[MaxN],Down_two[MaxN],Son[MaxN];
int Total,Side,Limit,Cnt;
int u,v,w,Opt,Ans;
int Next[MaxN<<1],Head[MaxN],End[MaxN<<1],Cur;
bool Jud[MaxN];

inline void File() {
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
}

inline void DFS_two(int New,int Pre) {
    int Temp;
    if(Son[Pre]==New) { Temp=(Jud[Pre] ? max(1,max(Down_two[Pre] ? Down_two[Pre]+1 : 0,Up[Pre] ? Up[Pre]+1 : 0)) : max(Down_two[Pre] ? Down_two[Pre]+1 : 0,Up[Pre] ? Up[Pre]+1 : 0)); }
    else { Temp=(Jud[Pre] ? max(1,max(Down_one[Pre] ? Down_one[Pre]+1 : 0,Up[Pre] ? Up[Pre]+1 : 0)) : max(Down_one[Pre] ? Down_one[Pre]+1 : 0,Up[Pre] ? Up[Pre]+1 : 0)); }
    Up[New]=max(Up[New],Temp);
    if(Down_one[New]<=Limit && Up[New]<=Limit) Ans++;
    for(int i=Head[New];i;i=Next[i]) {
        if(End[i]==Pre) continue;
        DFS_two(End[i],New);
    }
}

inline void DFS_one(int New,int Pre) {
    for(int i=Head[New];i;i=Next[i]) {
        if(End[i]==Pre) continue;
        DFS_one(End[i],New);
        int Temp=(Jud[End[i]] ? max(1,Down_one[End[i]] ? Down_one[End[i]]+1 : 0) : (Down_one[End[i]] ? Down_one[End[i]]+1 : 0));
        if(Temp>Down_one[New]) { Down_two[New]=Down_one[New]; Down_one[New]=Temp; Son[New]=End[i]; }
        else if(Temp>Down_two[New]) { Down_two[New]=Temp; }
        // FOR(i,1,Total) { cout<<"i: "<<i<<" Down_two: "<<Down_two[i]<<" Down_one: "<<Down_one[i]<<" Up: "<<Up[i]<<endl; }
    }
}

inline void Add_Edge(int From,int To) { Next[++Cur]=Head[From]; Head[From]=Cur; End[Cur]=To; }
int main() {
    // File();
    ios::sync_with_stdio(false);
    cin>>Total>>Cnt>>Limit;
    FOR(i,1,Cnt) { cin>>u; Jud[u]=true; } 
    FOR(i,1,Total-1) { cin>>u>>v; Add_Edge(u,v); Add_Edge(v,u); }
    DFS_one(1,0);
    DFS_two(1,0);
    // FOR(i,1,Total) { cout<<"i: "<<i<<" Down_two: "<<Down_two[i]<<" Down_one: "<<Down_one[i]<<" Up: "<<Up[i]<<endl; }
    cout<<Ans<<endl;
    // fclose(stdin);
    // fclose(stdout);
    system("pause");
    return 0;
}