You are given a rooted tree consisting of n n n vertices numbered from 1 1 1 to n n n. The root of the tree is a vertex number 1 1 1.
A tree is a connected undirected graph with n − 1 n-1 n−1 edges.
You are given m m m queries. The i i i-th query consists of the set of k i k_i ki distinct vertices v i [ 1 ] , v i [ 2 ] , … , v i [ k i ] v_i[1], v_i[2], \dots, v_i[k_i] vi[1],vi[2],…,vi[ki]. Your task is to say if there is a path from the root to some vertex u u u such that each of the given k k k vertices is either belongs to this path or has the distance 1 1 1 to some vertex of this path.
Input
The first line of the input contains two integers n n n and m m m ( 2 ≤ n ≤ 2 ⋅ 1 0 5 2 \le n \le 2 \cdot 10^5 2≤n≤2⋅105, 1 ≤ m ≤ 2 ⋅ 1 0 5 1 \le m \le 2 \cdot 10^5 1≤m≤2⋅105) — the number of vertices in the tree and the number of queries.
Each of the next n − 1 n-1 n−1 lines describes an edge of the tree. Edge i i i is denoted by two integers u i u_i ui and v i v_i vi, the labels of vertices it connects ( 1 ≤ u i , v i ≤ n , u i ≠ v i (1 \le u_i, v_i \le n, u_i \ne v_i (1≤ui,vi≤n,ui=vi).
It is guaranteed that the given edges form a tree.
The next m m m lines describe queries. The i i i-th line describes the i i i-th query and starts with the integer k i k_i ki ( 1 ≤ k i ≤ n 1 \le k_i \le n 1≤ki≤n) — the number of vertices in the current query. Then k i k_i ki integers follow: v i [ 1 ] , v i [ 2 ] , … , v i [ k i ] v_i[1], v_i[2], \dots, v_i[k_i] vi[1],vi[2],…,vi[ki] ( 1 ≤ v i [ j ] ≤ n 1 \le v_i[j] \le n 1≤vi[j]≤n), where v i [ j ] v_i[j] vi[j] is the j j j-th vertex of the i i i-th query.
It is guaranteed that all vertices in a single query are distinct.
It is guaranteed that the sum of k i k_i ki does not exceed 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105 ( ∑ i = 1 m k i ≤ 2 ⋅ 1 0 5 \sum\limits_{i=1}^{m} k_i \le 2 \cdot 10^5 i=1∑mki≤2⋅105).
Output
For each query, print the answer — “YES”, if there is a path from the root to some vertex u u u such that each of the given k k k vertices is either belongs to this path or has the distance 1 1 1 to some vertex of this path and “NO” otherwise.
Example
Input
Copy
10 6
1 2
1 3
1 4
2 5
2 6
3 7
7 8
7 9
9 10
4 3 8 9 10
3 2 4 6
3 2 1 5
3 4 8 2
2 6 10
3 5 4 7
Output
Copy
YES
YES
YES
YES
NO
NO
Note
The picture corresponding to the example:
Consider the queries.
The first query is [ 3 , 8 , 9 , 10 ] [3, 8, 9, 10] [3,8,9,10]. The answer is “YES” as you can choose the path from the root 1 1 1 to the vertex u = 10 u=10 u=10. Then vertices [ 3 , 9 , 10 ] [3, 9, 10] [3,9,10] belong to the path from 1 1 1 to 10 10 10 and the vertex 8 8 8 has distance 1 1 1 to the vertex 7 7 7 which also belongs to this path.
The second query is [ 2 , 4 , 6 ] [2, 4, 6] [2,4,6]. The answer is “YES” as you can choose the path to the vertex u = 2 u=2 u=2. Then the vertex 4 4 4 has distance 1 1 1 to the vertex 1 1 1 which belongs to this path and the vertex 6 6 6 has distance 1 1 1 to the vertex 2 2 2 which belongs to this path.
The third query is [ 2 , 1 , 5 ] [2, 1, 5] [2,1,5]. The answer is “YES” as you can choose the path to the vertex u = 5 u=5 u=5 and all vertices of the query belong to this path.
The fourth query is [ 4 , 8 , 2 ] [4, 8, 2] [4,8,2]. The answer is “YES” as you can choose the path to the vertex u = 9 u=9 u=9 so vertices 2 2 2 and 4 4 4 both have distance 1 1 1 to the vertex 1 1 1 which belongs to this path and the vertex 8 8 8 has distance 1 1 1 to the vertex 7 7 7 which belongs to this path.
The fifth and the sixth queries both have answer “NO” because you cannot choose suitable vertex u u u.
本题给定一棵有根树,树中包含 n n n 个从 1 1 1 到 n n n 编号的顶点,根节点为顶点 1 1 1。同时还会给出 m m m 个查询,每个查询包含一组不同的顶点。对于每个查询,需要判断是否存在一条从根节点到某个顶点 u u u 的路径,使得查询中的每个顶点要么属于这条路径,要么与路径上的某个顶点距离为 1 1 1。
对于每个查询,如果存在满足条件的路径,输出 “YES”,否则输出 “NO”。
选择最深顶点:在每个查询中,选择一个距离根节点最远的顶点 f v fv fv。因为若存在满足条件的路径,它大概率会延伸到这个最深顶点。
顶点替换:将查询中除根节点和 f v fv fv 之外的每个顶点替换为其父节点。这样做是为了将距离路径为 1 1 1 的顶点转化为路径上的顶点来处理。
路径判断:检查替换后的每个顶点是否都在从根节点到 f v fv fv 的路径上。为了实现这一判断,使用深度优先搜索(DFS)预处理每个顶点的进入时间 tin
和离开时间 tout
。利用这两个时间信息,通过判断区间包含关系来确定一个顶点是否是另一个顶点的父节点,进而判断一个顶点是否在从根节点到 f v fv fv 的路径上。 ### 代码分析
代码主要由以下几个部分组成:
头文件和常量定义:包含了常用的头文件,定义了一些常量,如 MAXN
和 LOG
,用于确定最大节点数和倍增算法所需的对数。
全局变量:定义了节点数 n n n、查询数 m m m、树的邻接表 tree
、倍增数组 up
和深度数组 depth
。
DFS 函数:用于预处理每个节点的父节点信息和深度信息,同时进行倍增数组的初始化。
LCA 函数:使用倍增算法查找两个节点的最近公共祖先(LCA)。
solved
函数:处理输入,调用 dfs
函数进行预处理,然后处理每个查询。
主函数:初始化输入输出流,调用 solved
函数解决问题。
#include
dfs
函数 - 接收当前节点 u
、父节点 parent
和深度 dep
作为参数。
初始化 up[u][0]
为父节点,depth[u]
为当前深度。
通过倍增算法预处理 up
数组,用于快速查找祖先节点。
递归调用 dfs
函数处理子节点。
2.lca
函数 - 首先比较两个节点的深度,将较深的节点提升到与较浅节点相同的深度。 - 然后通过倍增算法向上跳跃,直到找到两个节点的最近公共祖先。
solved
函数 - 读取输入的节点数 n n n 和查询数 q q q,构建树的邻接表。 - 调用 dfs
函数进行预处理。 - 对于每个查询,读取查询中的顶点数 k k k 和顶点列表。 - 将非根节点替换为其父节点,并找到最深的顶点 depp
。 - 检查每个顶点是否在从根节点到 depp
的路径上,通过判断 lca(v[i], depp)
是否等于 v[i]
来实现。 - 根据检查结果输出 “YES” 或 “NO”。solved
函数解决问题。整体时间复杂度为 O ( n + m ) O(n + m) O(n+m),其中 n n n 是树的节点数, m m m 是查询数。主要开销在于 DFS 预处理和每个查询的处理。