Codeforces Round #629 (Div. 3) E.Tree Queries (DFS)

思路:若ai 在路径上 ,则ai的父结点一定在路径上,若ai是路径上某个结点的子结点,则ai的父结点一定在路径上,综上只需考虑ai的父节点就行了。对每个ai判断一下ai-1是否能到达ai,若存一个不行则输出NO,反之输出YES.
用f[i]存储父结点,用dfs[i]记录访问顺序,用sz[i]保存 子树结点数。详情见代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,h[N],sz[N],dfn[N],cnt,f[N],num,a[N];//sz[i]储存结点以结点i为根的子树的结点数,f[i]储存i的父结点. 
struct  edge{//边 
	int to,nt;
}e[N<<1];
void add(int u,int v){//链式前向星。 
	cnt++;
	e[cnt].to=v;
	e[cnt].nt=h[u];
	h[u]=cnt;
}
void dfs(int u,int fa){ //dfs 
	  f[u]=fa;
	  dfn[u]=++num;//储存访问顺序 
	  sz[u]=1;//初始化 
	  for(int i=h[u];i;i=e[i].nt)
	  {
	  		int v=e[i].to;
	  		if(v!=fa){
	  			dfs(v,u);
	  			sz[u]+=sz[v];
			}
	  }
}
bool cmp(int a,int b){ //按访问顺序排序 
	return dfn[a]<dfn[b];
}
int main(){
	cin>>n>>m;
	ios::sync_with_stdio(false),cin.tie(0);
	for(int i=1,u,v;i<n;i++){
		cin>>u>>v;
		add(u,v),add(v,u);
	}
	dfs(1,0);
	while(m--){
		int k;
		cin>>k;
		for(int i=1;i<=k;i++){
			cin>>a[i];
			if(a[i]!=1) a[i]=f[a[i]];//特判 因为1没有父结点 
		}
		sort(a+1,a+k+1,cmp);
		int ok=1;
		for(int i=2;i<=k;i++)
			if(dfn[a[i-1]]+sz[a[i-1]]-1<dfn[a[i]]) //若a[i-1]到达不了a[i] 
				{
					ok=0;
					break;
				}
		puts(ok?"YES":"NO");
	}
	return 0;
}