- 题意:给一个以1为根节点树,m次询问,每次选k个节点,问是否存在一个节点u,在1~u的路径上所有这k个点到这条路径的距离都小于等于1。
- 题解:d[]记录每个点到根节点的距离,这个u一定是k个点中d[]最大的那个点。然后判断其他点满足条件吗。判断方法就是看d[a[i]] - d[lca(u, a[i])] 是否都小于 1。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 2e5 + 105;
const int mod = 1e9 + 7;
const double Pi = 3.1415926;
const ll INF = 0x3f3f3f3f;
int n, m, t, k, flag = 0;
int head[N], cnt = 0;
int d[N], a[N], f[N][20];
struct node{
int to;
int nxt;
}edge[4 * N];
queue<int>q;
inline void add(int x, int y){
edge[cnt].to = y;
edge[cnt].nxt = head[x];
head[x] = cnt ++;
}
void bfs(){
q.push(1);
d[1] = 1;
while(!q.empty()){
int x = q.front();
q.pop();
for(int i = head[x]; i != -1; i = edge[i].nxt){
int y = edge[i].to;
if(d[y]) continue;
d[y] = d[x] + 1;
f[y][0] = x;
for(int j = 1; j <= t; ++ j)
f[y][j] = f[f[y][j - 1]][j - 1];
q.push(y);
}
}
}
int LCA(int x, int y){
if(d[x] > d[y]) swap(x, y);
for(int i = t; i >= 0; -- i)
if(d[f[y][i]] >= d[x]) y = f[y][i];
if(x == y) return x;
for(int i = t; i >= 0; -- i)
if(f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
return f[x][0];
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d",&n,&m);
t = (int)(log(n) / log(2)) + 1;
for(int i = 1; i < n; ++ i){
int x, y;
scanf("%d%d",&x,&y);
add(x, y);
add(y, x);
}
bfs();
while(m --){
scanf("%d",&k);
flag = 0;
int base = 0, maxx = 0;
for(int i = 1; i <= k; ++ i){
scanf("%d",&a[i]);
if(d[a[i]] > maxx){
maxx = d[a[i]];
base = a[i];
}
}
for(int i = 1; i <= k; ++ i){
if(base == a[i]) continue;
int lca = LCA(base, a[i]);
if(d[a[i]] - d[lca] > 1) flag = 1;
}
if(!flag) printf("YES
");
else printf("NO
");
}
return 0;
}