#include<bits/stdc++.h>
#define AUTO(i,u) for(int (i)=G.head[(u)];(i)!=-1;(i)=G.nxt[i])
using namespace std;
int N,M,S;
int deep[200010];
int st[200010][30];
struct Grape{
int head[200010];
int nxt[400010];
int to[400010];
void Emplace_back(int u,int v){
to[++c]=v;
nxt[c]=head[u];
head[u]=c;
return;
}
void clear(void){
*this=Grape();
return;
}
Grape(){
c=0;
memset(head,-1,sizeof head);
memset(nxt,-1,sizeof nxt);
memset(to,0,sizeof to);
}
int c;
}G;
int fa[200001];
bool cmp(int x,int y){
return deep[x]<deep[y];
}
void InitDeep(int u,int par){
deep[u]=deep[par]+1;
st[u][0]=par;
fa[u]=par;
for(int i=1;(1<<i)<=deep[u];i++){
st[u][i]=st[st[u][i-1]][i-1];
}
AUTO(i,u){
int To=G.to[i];
if(To!=par)InitDeep(To,u);
}
return;
}
int LCA(int a,int b){
if(deep[a]>deep[b])swap(a,b);
for(int i=20;i>=0;i--){
if(deep[a]<=deep[b]-(1<<i)){
b=st[b][i];
}
}
if(a==b)return a;
for(int i=20;i>=0;i--){
if(st[a][i]==st[b][i]){
continue;
}
a=st[a][i];
b=st[b][i];
}
return st[a][0];
}
int ans=0;
int q[200001];
bool vis[200001];
void DFS(int u,int ppar){
vis[u]=true;
if(u==ppar){
return;
}
DFS(fa[u],ppar);
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
srand(time(0));
cin>>N>>M;S=rand()%N;
for(int i=1;i<N;i++){
int u,v;
cin>>u>>v;
G.Emplace_back(u,v);
G.Emplace_back(v,u);
}
InitDeep(S,0);
for(int i=1;i<=M;i++){
cin>>q[i];vis[q[i]]=1;
}
sort(q+1,q+1+M,cmp);
for(int i=1;i<M;i++){
int lca=LCA(q[i],q[i+1]);
// cout<<lca<<' '<<q[i]<<' '<<q[i+1]<<'\n';
DFS(q[i],lca);
DFS(q[i+1],lca);
}
for(int i=1;i<=N;i++){
if(vis[i])ans++;
}
cout<<ans;
return 0;
}
大致思路是用 LCA 解决,排序弄掉尽可能多的重复节点遍历,而有时树会退化为链,将根节点随机设定。