题意:
一
个
国
家
有
n
个
城
市
,
形
成
一
棵
树
,
有
n
−
1
条
边
一个国家有n个城市,形成一棵树,有n-1条边
一个国家有n个城市,形成一棵树,有n−1条边
国
家
中
有
k
个
帮
派
,
分
别
占
领
一
些
城
市
国家中有k个帮派,分别占领一些城市
国家中有k个帮派,分别占领一些城市
每
个
帮
派
占
领
c
i
个
城
市
,
以
及
这
c
i
个
城
市
路
径
上
的
所
有
点
每个帮派占领c_i个城市,以及这c_i个城市路径上的所有点
每个帮派占领ci个城市,以及这ci个城市路径上的所有点
帮
派
可
以
联
盟
,
联
盟
会
将
几
个
帮
派
的
所
有
占
领
城
市
和
路
径
上
的
城
市
占
领
帮派可以联盟,联盟会将几个帮派的所有占领城市和路径上的城市占领
帮派可以联盟,联盟会将几个帮派的所有占领城市和路径上的城市占领
q
次
询
问
,
首
都
如
果
建
在
v
城
市
q次询问,首都如果建在v城市
q次询问,首都如果建在v城市
求
首
都
离
给
定
t
i
个
帮
派
联
盟
中
最
近
占
领
城
市
的
距
离
求首都离给定t_i个帮派联盟中最近占领城市的距离
求首都离给定ti个帮派联盟中最近占领城市的距离
题解:
由
于
这
是
一
棵
树
,
路
径
只
有
一
条
,
那
么
就
假
设
根
为
1
由于这是一棵树,路径只有一条,那么就假设根为1
由于这是一棵树,路径只有一条,那么就假设根为1
那
么
就
可
以
用
L
C
A
找
到
这
些
帮
派
占
领
的
最
高
的
父
亲
节
点
那么就可以用LCA找到这些帮派占领的最高的父亲节点
那么就可以用LCA找到这些帮派占领的最高的父亲节点
求
出
每
个
帮
派
的
L
C
A
后
,
联
盟
的
时
候
,
找
这
几
个
帮
派
的
L
C
A
求出每个帮派的LCA后,联盟的时候,找这几个帮派的LCA
求出每个帮派的LCA后,联盟的时候,找这几个帮派的LCA
如
果
发
现
首
都
不
在
这
个
L
C
A
的
子
树
中
,
那
肯
定
最
短
距
离
就
是
到
这
个
L
C
A
的
距
离
如果发现首都不在这个LCA的子树中,那肯定最短距离就是到这个LCA的距离
如果发现首都不在这个LCA的子树中,那肯定最短距离就是到这个LCA的距离
树
上
两
点
距
离
可
以
用
两
点
的
深
度
和
减
去
2
倍
两
点
L
C
A
的
深
度
求
解
树上两点距离可以用两点的深度和减去2倍两点LCA的深度求解
树上两点距离可以用两点的深度和减去2倍两点LCA的深度求解
然
后
就
要
考
虑
如
果
首
都
建
在
这
个
子
树
里
然后就要考虑如果首都建在这个子树里
然后就要考虑如果首都建在这个子树里
子
树
里
可
能
刚
好
在
联
盟
占
领
的
城
市
里
,
或
者
不
在
子树里可能刚好在联盟占领的城市里,或者不在
子树里可能刚好在联盟占领的城市里,或者不在
由
于
每
次
询
问
给
出
的
联
盟
帮
派
个
数
不
是
很
多
由于每次询问给出的联盟帮派个数不是很多
由于每次询问给出的联盟帮派个数不是很多
所
以
直
接
暴
力
枚
举
这
些
联
盟
帮
派
,
找
最
近
点
所以直接暴力枚举这些联盟帮派,找最近点
所以直接暴力枚举这些联盟帮派,找最近点
这
时
候
就
要
用
到
d
f
s
序
这时候就要用到dfs序
这时候就要用到dfs序
利
用
二
分
在
每
个
帮
派
占
领
的
城
市
中
,
找
到
距
离
首
都
城
市
最
近
的
两
个
城
市
利用二分在每个帮派占领的城市中,找到距离首都城市最近的两个城市
利用二分在每个帮派占领的城市中,找到距离首都城市最近的两个城市
也
就
是
第
一
个
大
于
等
于
他
,
和
第
一
个
小
于
他
的
城
市
也就是第一个大于等于他,和第一个小于他的城市
也就是第一个大于等于他,和第一个小于他的城市
(
因
为
找
的
是
大
于
等
于
,
如
果
有
等
于
的
情
况
就
说
明
首
都
就
是
被
占
领
点
,
结
果
是
0
)
(因为找的是大于等于,如果有等于的情况就说明首都就是被占领点,结果是0)
(因为找的是大于等于,如果有等于的情况就说明首都就是被占领点,结果是0)
由
于
首
都
是
在
联
盟
的
L
C
A
的
子
树
中
,
所
以
找
到
的
这
两
个
被
占
领
的
城
市
由于首都是在联盟的LCA的子树中,所以找到的这两个被占领的城市
由于首都是在联盟的LCA的子树中,所以找到的这两个被占领的城市
到
他
们
父
亲
结
点
的
路
径
一
定
全
部
都
是
被
占
领
的
到他们父亲结点的路径一定全部都是被占领的
到他们父亲结点的路径一定全部都是被占领的
所
以
想
要
找
最
近
的
,
就
应
该
找
到
首
都
和
他
们
的
L
C
A
所以想要找最近的,就应该找到首都和他们的LCA
所以想要找最近的,就应该找到首都和他们的LCA
这
个
图
中
,
假
设
黑
色
是
被
占
领
点
,
如
果
1
和
4
被
占
领
这个图中,假设黑色是被占领点,如果1和4被占领
这个图中,假设黑色是被占领点,如果1和4被占领
1
就
是
这
个
联
盟
占
领
的
最
高
点
,
将
在
6
建
首
都
,
6
在
最
高
点
的
子
树
中
1就是这个联盟占领的最高点,将在6建首都,6在最高点的子树中
1就是这个联盟占领的最高点,将在6建首都,6在最高点的子树中
标
注
的
123456
代
表
的
就
是
d
f
s
序
,
6
相
邻
最
近
被
占
领
的
点
是
4
标注的123456代表的就是dfs序,6相邻最近被占领的点是4
标注的123456代表的就是dfs序,6相邻最近被占领的点是4
但
是
4
到
6
的
距
离
明
显
没
有
1
到
6
近
,
所
以
要
进
行
对
4
和
6
求
L
C
A
但是4到6的距离明显没有1到6近,所以要进行对4和6求LCA
但是4到6的距离明显没有1到6近,所以要进行对4和6求LCA
然
后
再
计
算
这
个
L
C
A
到
6
的
距
离
才
是
最
近
的
然后再计算这个LCA到6的距离才是最近的
然后再计算这个LCA到6的距离才是最近的
找
第
一
个
大
于
等
于
首
都
d
f
s
序
的
点
也
是
类
似
道
理
找第一个大于等于首都dfs序的点也是类似道理
找第一个大于等于首都dfs序的点也是类似道理
这
个
图
没
有
表
示
全
部
情
况
,
只
举
例
说
了
一
下
找
第
一
个
小
于
的
这个图没有表示全部情况,只举例说了一下找第一个小于的
这个图没有表示全部情况,只举例说了一下找第一个小于的
然
后
在
这
两
个
点
都
能
取
到
的
情
况
下
取
最
小
结
果
,
就
是
最
终
答
案
然后在这两个点都能取到的情况下取最小结果,就是最终答案
然后在这两个点都能取到的情况下取最小结果,就是最终答案
AC代码
/*
Author : zzugzx
Lang : C++
Blog : blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod = 1e9+7;
//const int mod = 998244353;
const double eps = 1e-10;
const double pi = acos(-1.0);
const int maxn = 1e6+10;
const ll inf = 0x3f3f3f3f;
const int dir[][2]={{0, 1}, {1, 0}, {0, -1}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
int n,depth[maxn], f[maxn][50];
int from[maxn], to[maxn << 1], nxt[maxn << 1], cnt, Log[maxn];
int L[maxn], R[maxn], id, pos[maxn], top[maxn];
void addEdge (int u, int v) {
to[++cnt] = v, nxt[cnt] = from[u], from[u] = cnt;
}
void dfs (int u, int fa) {
depth[u] = depth[fa] + 1;
L[u] = ++id;
pos[id] = u;
for (register int i = 1; i <= Log[n]; ++i) {
if ((1 << i) > depth[u]) break;
f[u][i] = f[f[u][i - 1]][i - 1];
}
for (register int i = from[u]; i; i = nxt[i]) {
ll v = to[i];
if (v == fa) continue;
f[v][0] = u;
dfs (v, u);
}
R[u] = id;
}
inline int LCA (int x, int y) {
if (depth[x] < depth[y]) swap(x, y);
for(register int i = Log[n] ; i >= 0 ; --i)
if(depth[x] - (1 << i) >= depth[y]) x = f[x][i];
if (x == y) return x;
for (register int i = Log[n]; i >= 0; --i)
if (f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
return f[x][0];
}
void init(){
Log[0] = -1;
for (register int i = 1, u, v; i < n; ++i) {
cin >> u >> v;
addEdge (u, v); addEdge(v, u);
Log[i] = Log[i >> 1] + 1;
}
Log[n] = Log[n >> 1] + 1;
dfs(1,0);
}
int dis(int p , int q){return depth[p] + depth[q] - 2 * depth[LCA(p , q)];}
vector<int> g[maxn];
int a[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
cin >> n;
init();
int q;
cin >> q;
for (int i = 1; i <= q; i++) {
int k;
cin >> k;
for(int j = 1; j <= k; j++) {
int x;
cin >> x;
g[i].pb(L[x]);
if (j == 1) top[i] = x;
else top[i] = LCA(top[i], x);
}
sort(all(g[i]));
}
cin >> q;
while (q--) {
int v, t;
cin >> v >> t;
int rt;
for (int i = 1; i <= t; i++){
cin >> a[i];
if (i == 1) rt = top[a[i]];
else rt = LCA(rt, top[a[i]]);
}
if (L[v] < L[rt] || L[v] > R[rt]) {
cout << dis(v, rt) << endl;
continue;
}
int ans = inf;
for (int i = 1; i <= t; i++){
auto p = lower_bound(all(g[a[i]]), L[v]);
if (p != g[a[i]].end())
ans = min(ans, dis(v, LCA(v, pos[*p])));
if (p !=g[a[i]].begin())
ans = min(ans, dis(v, LCA(v, pos[*prev(p)])));
}
cout << ans << endl;
}
return 0;
}