题解思路:这题就求最近公共祖先,找出S集合中的深度最深的点,然后与其他点的最远距离取max然后除以二就是答案(肯定在中间是最好的).
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int mx = 3e5+10;
int n,m,head[mx],tot;
struct node{
int y,nxt;
}Edge[mx<<1];
void AddEdge(int x,int y){
Edge[tot].y = y;
Edge[tot].nxt = head[x];
head[x] = tot++;
}
int deep[mx],fa[mx][21];
void dfs(int x,int f){//深搜寻找深度可定父节点
int son;
for(int i=head[x];~i;i=Edge[i].nxt){
son = Edge[i].y;
if(son == f) continue;
deep[son] = deep[x]+1;
fa[son][0] = x;
dfs(son,x);
}
}
void RMQ(){//RMQfa[i]的2^j祖先
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int LCA(int u,int v){
if(deep[u]<deep[v]) swap(u,v);
int i,j;
i=log(deep[u])/log(2.0);
for(j=i;j>=0;j--)
if((deep[u]-(1<<j))>=deep[v])
u=fa[u][j];//使u和v相同深度
if(u==v) return u;
for(j=i;j>=0;j--){
if(fa[u][j]!=fa[v][j]){//不断逼近
u=fa[u][j];
v=fa[v][j];
}
}
return fa[u][0];
}
int num[mx];
int main()
{
while(~scanf("%d",&n))
{
int a,b,q;
tot = 0;
memset(head,-1,sizeof(head));
//memset(deep,0,sizeof(deep));
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
AddEdge(a,b);
AddEdge(b,a);
}
dfs(1,0);
RMQ();
scanf("%d",&a);
while(a--)
{
scanf("%d",&m);
int p = 1,ans = 0;
for(int i=1; i<=m; i++)
{
scanf("%d",&num[i]);
if(deep[num[i]]>deep[p])
p=num[i];
}
for(int i=1; i<=m; i++)
{
int a=num[i];
int f=LCA(p,a);
int l=deep[p]+deep[a]-2*deep[f];
if(l>ans) ans=l;
}
printf("%d\n",(ans+1)/2);
}
}
return 0;
}