題目鏈接:https://codeforces.com/contest/1328/problem/E
題意:給你一棵樹,多次詢問每次給你一個集合,問你能否選一條鏈使得集合所有點到這條鏈的距離不大於1
思路:每次將集合按照深度排序,然後我們用深度最大的點和其餘點依次求LCA,然後判斷深度差是否大於1
如果大於就說明不滿足。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fi first
#define se second
#define ls rt << 1
#define rs rt << 1|1
#define lson l, mid, ls
#define rson mid + 1, r, rs
#define pll pair<ll, ll>
#define pii pair<int, int>
#define ull unsigned long long
#define pdd pair<double, double>
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
//head[u] 和 tot的初始值都爲-1
int head[maxn << 1], nxt[maxn << 1], to[maxn << 1], ver[maxn << 1];
int f[maxn][22], d[maxn], dis[maxn], a[maxn]; //d[x]表示x的深度, dis[y]表示y到根的距離
int n, m, s, lg, tot = -1;
queue<int> q;
void add(int u, int v, int w)
{
nxt[++tot] = head[u]; //當前邊的後繼
head[u] = tot; //起點u的第一條邊
to[tot] = v; //當前邊的終點
ver[tot] = w; //當前邊的權值
}
void bfs(int s)
{
while(!q.empty()) q.pop();
q.push(s), d[s] = 1;
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = nxt[i])
{
int v = to[i];
if(d[v]) continue;
d[v] = d[u] + 1;
dis[v] = dis[u] + ver[i];
f[v][0] = u;
for(int j = 1; j <= lg; ++j)
f[v][j] = f[f[v][j - 1]][j - 1];
q.push(v);
}
}
}
int LCA(int u, int v)
{
if(d[u] > d[v]) swap(u, v);
for(int i = lg; i >= 0; --i) //u是v的祖先的情況
{
if(d[f[v][i]] >= d[u]) //不在同一條鏈上就處理到深度相同
v = f[v][i];
}
if(u == v) return u;
for(int i = lg; i >= 0; --i) //深度相同就可以同時倍增求
{
if(f[u][i] != f[v][i])
u = f[u][i], v = f[v][i];
}
return f[u][0];
}
int main()
{
scanf("%d%d", &n, &m);
lg = (int)(log(n) / log(2)) + 1; //枚舉的深度
for(int i = 0; i <= n; ++i) head[i] = -1, d[i] = 0;
tot = -1;
for(int i = 1; i < n; ++i)
{
int u, v, w = 1;
scanf("%d%d", &u, &v);
add(u, v, w), add(v, u, w);
}
bfs(1); //s是根節點
while(m--)
{
int k, Max = 0, id;
scanf("%d", &k);
for(int i = 1; i <= k; ++i)
{
scanf("%d", &a[i]);
if(Max < d[a[i]])
Max = d[a[i]], id = a[i];
}
int flag = 1;
for(int i = 1; i <= k; ++i)
{
int fa = LCA(id, a[i]);
if(abs(d[fa] - d[a[i]]) > 1)
{
flag = 0;
break;
}
}
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}