Tree Queries CodeForces - 1328E (DFS序)

outputstandard output
You are given a rooted tree consisting of n vertices numbered from 1 to n. The root of the tree is a vertex number 1.

A tree is a connected undirected graph with n−1 edges.

You are given m queries. The i-th query consists of the set of ki distinct vertices vi[1],vi[2],…,vi[ki]. Your task is to say if there is a path from the root to some vertex u such that each of the given k vertices is either belongs to this path or has the distance 1 to some vertex of this path.

Input
The first line of the input contains two integers n and m (2≤n≤2⋅105, 1≤m≤2⋅105) — the number of vertices in the tree and the number of queries.

Each of the next n−1 lines describes an edge of the tree. Edge i is denoted by two integers ui and vi, the labels of vertices it connects (1≤ui,vi≤n,ui≠vi).

It is guaranteed that the given edges form a tree.

The next m lines describe queries. The i-th line describes the i-th query and starts with the integer ki (1≤ki≤n) — the number of vertices in the current query. Then ki integers follow: vi[1],vi[2],…,vi[ki] (1≤vi[j]≤n), where vi[j] is the j-th vertex of the i-th query.

It is guaranteed that all vertices in a single query are distinct.

It is guaranteed that the sum of ki does not exceed 2⋅105 (∑i=1mki≤2⋅105).

Output
For each query, print the answer — “YES”, if there is a path from the root to some vertex u such that each of the given k vertices is either belongs to this path or has the distance 1 to some vertex of this path and “NO” otherwise.

Example
inputCopy
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
outputCopy
YES
YES
YES
YES
NO
NO
Note
The picture corresponding to the example:
在这里插入图片描述

Consider the queries.

The first query is [3,8,9,10]. The answer is “YES” as you can choose the path from the root 1 to the vertex u=10. Then vertices [3,9,10] belong to the path from 1 to 10 and the vertex 8 has distance 1 to the vertex 7 which also belongs to this path.

The second query is [2,4,6]. The answer is “YES” as you can choose the path to the vertex u=2. Then the vertex 4 has distance 1 to the vertex 1 which belongs to this path and the vertex 6 has distance 1 to the vertex 2 which belongs to this path.

The third query is [2,1,5]. The answer is “YES” as you can choose the path to the vertex u=5 and all vertices of the query belong to this path.

The fourth query is [4,8,2]. The answer is “YES” as you can choose the path to the vertex u=9 so vertices 2 and 4 both have distance 1 to the vertex 1 which belongs to this path and the vertex 8 has distance 1 to the vertex 7 which belongs to this path.

The fifth and the sixth queries both have answer “NO” because you cannot choose suitable vertex u.
思路:T到爆的一道题,本来以为思路已经很正确了,在76个样例上T到爆。
我的思路:按照深度排序之后,对于给定的点,我们找到深度最大的点,遍历它到根节点,并将这条链上的点标记。对于剩下的点,父节点一定是标记过的,否则就不对。这样一直T在76个样例,有可能每次都遍历一些点,这样很耗时吧。。
正解为dfs序。对于给出的点,父节点一定是在一条链上的。那么按照dfs序最小值排好序之后,遍历给定点的父节点数组,dfs序的顺序是不断缩小的,如果出现了交叉的情况,就肯定出错了。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=2e5+100;
struct edge{
	int next;
	int to;
}e[maxx<<1];
int head[maxx<<1],fa[maxx],L[maxx],R[maxx],b[maxx],c[maxx];
int n,m,k,tot;

inline int read() {
    char ch = getchar(); int x = 0, f = 1;
    while(ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    } while('0' <= ch && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    } return x * f;
}
inline bool cmp(int x,int y)
{
	return L[x]<L[y];
}
inline void init()
{
	memset(head,-1,sizeof(head));
	for(int i=1;i<=n;i++) fa[i]=0;
	tot=0;
}
inline void add(int u,int v)
{
	e[tot].next=head[u],e[tot].to=v,head[u]=tot++;
}
inline void dfs(int u,int &num,int f)
{
	fa[u]=(u==1?1:f);
	L[u]=num;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		int to=e[i].to;
		if(to!=f) dfs(to,num+=1,u);
	}
	R[u]=num;
}

int main()
{
	n=read(),m=read();
	int x,y;
	init();
	for(int i=1;i<n;i++)
	{
		x=read(),y=read();
		add(x,y);
		add(y,x);
	}
	int num=1;
	dfs(1,num,0);
	for(int oo=1;oo<=m;oo++)
	{
		k=read();
		int _max=-1,pos;
		for(int i=1;i<=k;i++) 
		{
			b[i]=read();
			c[i]=fa[b[i]];
		}
		sort(c+1,c+1+k,cmp);
		int mk=1;
		int l=0,r=maxx;
		for(int i=1;i<=k;i++)
		{
			if(L[c[i]]>=l&&R[c[i]]<=r)//不断的缩短距离。
			{
				l=L[c[i]];
				r=R[c[i]];
			}
			else 
			{
				mk=0;
				break;
			}
		}
		if(mk) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

心酸历程
在这里插入图片描述
努力加油a啊,(o)/~

发布了596 篇原创文章 · 获赞 47 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/starlet_kiss/article/details/105164514