Problem - G2 - CodeforcesCodeforces. Programming competitions and contests, programming communityhttps://codeforces.com/contest/1702/problem/G2题意为给出一个树,再给出q个查询,每个查询给出树上点的子集,问这一串点能否构成树上的一个简单通路很明显这一题可以用LCA求解,首先我们要确定链的两端点,我们可以先求出最深的那个点,然后求另一个子树的最深节点,如果求不出另一个端点那肯定都在一条链上直接YES就行
然后我们就可以通过lca判断除断电外的点到两端点的距离是否等于两端点距离,通过这个可以判断是否在链上。
int head[MAXN];
int nxt[MAXN];
int ver[MAXN];
int cnt;
int Log2[MAXN];
int dep[MAXN];
int Fa[MAXN][21];
void add(int x, int y) {
ver[++cnt] = y;
nxt[cnt] = head[x];
head[x] = cnt;
}
void dfs(int p, int fa) {
Fa[p][0] = fa;
for (int i = 1; i <= Log2[dep[p]]; i++) {
Fa[p][i] = Fa[Fa[p][i - 1]][i - 1];
}
for (int i = head[p]; i; i = nxt[i]) {
int v = ver[i];
if (v == fa)
continue;
dep[v] = dep[p] + 1;
dfs(v, p);
}
}
int lca(int x, int y) {
if (dep[x] < dep[y])
swap(x, y);
while (dep[x] != dep[y]) {
x = Fa[x][Log2[dep[x] - dep[y]]];
}
if (x == y)
return x;
for (int i = Log2[dep[x]]; i >= 0; i--) {
if (Fa[x][i] != Fa[y][i])
x = Fa[x][i], y = Fa[y][i];
}
return Fa[x][0];
}
int Get_Dis(int x, int y) {
return dep[x] + dep[y] - 2 * dep[lca(x, y)];
}
void solve() {
int t;
scanf("%d", &t);
vector<int> v(t + 1);
int p1, p2;
for (int i = 1; i <= t; i++) {
scanf("%d", &v[i]);
}
p1 = v[1];
for (int i = 2; i <= t; i++) {
if (dep[p1] < dep[v[i]])
p1 = v[i];
}
p2 = 0;
for (int i = 1; i <= t; i++) {
if (v[i] == p1)
continue;
if (lca(p1, v[i]) != v[i]) {
if (p2 == 0)
p2 = v[i];
else if (dep[v[i]] > dep[p2])
p2 = v[i];
}
}
if (p2 == 0)
return void(printf("YES\n"));
int rec = Get_Dis(p1, p2);
bool flag = true;
for (int i = 1; i <= t; i++) {
if (v[i] == p1 || v[i] == p2)
continue;
if (Get_Dis(v[i], p1) + Get_Dis(v[i], p2) != rec) {
flag = false;
break;
}
}
if (flag)
printf("YES\n");
else
printf("NO\n");
}
int main() {
int n;
scanf("%d", &n);
for (int i = 2; i <= n; i++) {
Log2[i] = Log2[i / 2] + 1;
}
int x, y;
for (int i = 1; i <= n - 1; i++) {
scanf("%d %d", &x, &y);
add(x, y);
add(y, x);
}
dfs(1, 0);
int q;
scanf("%d", &q);
while (q--)
solve();
return 0;
}