题目链接:
解题报告:
最优点必然在点集S中最远两点的简单路径上且是中点。
个人解释:
假设u~v 为点集中拥有最远距离的简单路径,若最优点不在其上,那么 f(u)必然不是最小的,而题意是求min f(u);既然在该条简单路径上,那说明中点就是最优点
好多题解是建虚树,本人不会。
一些拓展知识
树的直径: 树上的最长简单路径。
解法:
原理:距某个点最远的叶子节点一定是树的某一条直径的端点。
那么可以任选一点求得一直径端点,再以该端点求最长路径。
待纠正!!
#define first f
#define second s
#define ll long long
#define mp make_pair
#define pb push_back
#define pf push_front
#define lb lower_bound
#define ub upper_bound
#include <bits/stdc++.h>
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=3e5+5;
const int MOD=998244353;
const double PI=acos(-1);
const double e=2.718281828459;
int deep[maxn],f[maxn][25];
vector<int>edge[maxn];
int p[maxn];
void dfs(int now,int pre)
{
deep[now]=deep[pre]+1;
f[now][0]=pre;
for(int i=1;i<=20;i++){
f[now][i]=f[f[now][i-1]][i-1];
}
for(int i=0,j;i<edge[now].size();i++){
j=edge[now][i];
if(j==pre){continue;}
dfs(j,now);
}
}
int LCA(int x,int y)
{
if(deep[x]<deep[y]){swap(x,y);}
for(int i=20;i>=0;i--){
if(deep[f[x][i]]>=deep[y]){x=f[x][i];}
}
if(x==y){return x;}
for(int i=20;i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int main()
{
int n,s,u,v,q;
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
edge[u].pb(v);
edge[v].pb(u);
}
deep[0]=0;
dfs(1,0);
scanf("%d",&q);
while(q--){
scanf("%d",&s);
int root=0,mx=-1;
for(int i=1;i<=s;i++){
scanf("%d",&p[i]);
if(deep[root]<deep[p[i]]){root=p[i];}
}
for(int i=1;i<=s;i++){
if(root==p[i]){continue;}
int pp=LCA(root,p[i]);
mx=max(mx,deep[root]+deep[p[i]]-2*deep[pp]);
}
printf("%d\n",(mx+1)/2);
}
return 0;
}