题意:给定一颗树,以及m个人,现在要求所有人到一个位置去,花费的时间是最后一个人到的时间,要求这个时间最小。
如果有n个人,这n个人构成一颗树,那么他们到某个地点去花费最小是不是树的直径除以2向上取整。
那现在是划定了m<=n,相当于求m个人的直径。
而求树的直径可以先一次bfs求得一个最远的点p,再从p出发bfs找到最远的点q,同时记录前驱,最后从q推回到p就可以了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
int s2,en;
queue<int> q;
bool vis[maxn];
int color[maxn];
int d[maxn];
int head[maxn],top;
void init(){
memset(head,-1,sizeof(head));
top=0;
}
struct Edge{
int v,next;
}edge[maxn<<1];
void add(int u,int v){
edge[top].v=v;
edge[top].next=head[u];
head[u]=top++;
}
void bfs(int st){
vis[st]=1;
q.push(st);
int u,v;
int maxx=0;
while(!q.empty()){
u=q.front(); q.pop();
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
if(vis[v]) continue;
vis[v]=1;
q.push(v);
d[v]=d[u]+1;
if(color[v]){
if(d[v]>maxx){
maxx=d[v];
s2=v;
}
}
}
}
}
int pre[maxn];
int bfs2(){
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(d));
while(!q.empty()) q.pop();
q.push(s2);
int u,v;
vis[s2]=1;
int maxx=0;
while(!q.empty()){
u=q.front(); q.pop();
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
if(vis[v]) continue;
vis[v]=1;
q.push(v);
d[v]=d[u]+1;
pre[v]=u;
if(color[v]){
if(d[v]>maxx){
maxx=d[v];
en=v;
}
}
}
}
int res=0;
while(en!=s2){
++res;
en=pre[en];
}
return res;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
init();
int u,v;
for(int i=1;i<n;++i){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
int x;
for(int i=1;i<=m;++i){
scanf("%d",&x);
color[x]=1;
}
if(m<=1) printf("0\n");
else{
bfs(x);
printf("%d\n",(bfs2()+1)/2);
}
return 0;
}