Link
思路:
前置知识 lca
树的的直径求法:最深的一个点一定是直径的一端
直径的中点到树上最远的距离最小。
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
int d[N], fa[N][21];
int n;`
int e[N<<2], ne[N<<2], h[N], cnt, p[N*10];
void add(int x, int y)
{
e[cnt] = y, ne[cnt] = h[x], h[x] = cnt ++;
e[cnt] = x, ne[cnt] = h[y], h[y] = cnt ++;
}
void dfs(int x, int f)
{
fa[x][0] = f;
for(int i = 1; i <= 20; i ++)
{
fa[x][i] = fa[fa[x][i - 1]][i - 1];
}
for(int i = h[x]; ~i; i = ne[i])
{
int v = e[i];
if(v == f) continue;
d[v] = d[x] + 1;
dfs(v, x);
}
}
int lca(int x, int y)
{
if(d[x] < d[y]) swap(x, y);
for(int i = 20; i >= 0; i --)
{
if(d[fa[x][i]] >= d[y])
{
x = fa[x][i];
}
}
if(x == y) return x;
for(int i = 20; i >= 0; i --)
{
int x1 = fa[x][i], y1 = fa[y][i];
if(x1 != y1) x = x1, y = y1;
}
return fa[x][0];
}
int dis(int x, int y)
{
return d[x] + d[y] - 2 * d[lca(x, y)];
}
int main()
{
cin >> n;
memset(h, -1, sizeof h);
for(int i = 1; i < n; i ++)
{
int x, y;
cin >> x >> y;
add(x, y);
}
dfs(1, 1);
// cout << fa[1][0] << endl;
// cout << d[1] << " " << d[2] << " " << d[3] << endl;
// cout << lca(3, 1) << " **" << endl;
int q;
cin >> q;
while(q --)
{
int m;
cin >> m;
int tt = 1;
for(int i = 1; i <= m; i ++)
{
cin >> p[i];
if(d[p[tt]] < d[p[i]]) tt = i;
}
int r = 0;
for(int i = 1; i <= m; i ++)
{
r = max(r, dis(p[tt], p[i]));
}
cout << (r + 1) / 2 << endl;
}
return 0;
}