Codeforces Round #629 (Div. 3) E. Tree Queries(LCA+思維)

題目鏈接
在這裏插入圖片描述
在這裏插入圖片描述
題意:給定n點,n-1條邊的樹,有m個詢問,每次詢問會給你一個數組,問你樹中是否存在着一條從1到某個點的路徑包含數組中的所有點,或者數組中的這些點距離這條路徑的路徑上的點的距離小於等於1.
思路:很明顯如果存在這條路徑的話,那麼給定的這些數組的點和路徑上的點要麼重合,要麼就是它的兄弟節點。比如第一個樣例,我們選最深的點10,然後就選擇樹上1到10的這條路徑,很顯然8和9是兄弟節點所以8也是符合條件的。我們用優先隊列來優先選擇深度最深的點,然後一步步向前推(這個地方一開始想用pre一步步推,結果tle test100.。。。),所以這個向前推的過程可以優化一下,用lca就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+1; 
int deep[maxn],pre[maxn],parent[maxn][22];
vector<int>g[maxn];
void dfs(int x,int fa)
{
	deep[x]=deep[fa]+1;
	pre[x]=fa;
	parent[x][0]=fa;
	for(int to:g[x])
	{
		if(to==fa) continue;
		dfs(to,x);
	}
 } 
struct cmp{
	bool  operator ()  ( int  a , int  b  ){
	   	      return deep[a]<deep[b];
	   } 
};
void init(int n)
{
	for(int k=1;k<=21;++k)
	for(int i=1;i<=n;++i)
	parent[i][k]=parent[parent[i][k-1]][k-1];
}
int main()
{
	 priority_queue < int , vector<int> , cmp  > q;
	int n,m,u,v,k,x;
	scanf("%d %d",&n,&m);
	for(int i=1;i<n;++i)
	{
		scanf("%d %d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	 } 
	 deep[1]=0;
	 dfs(1,0);
	 init(n);
	 while(m--)
	 {
	 	while(!q.empty())q.pop();
	 	scanf("%d",&k);
	 	for(int i=1;i<=k;++i)
	 	scanf("%d",&x),q.push(x);
	 	int t=q.top();q.pop();
	 	while(t!=0&&!q.empty())
	 	{
	 		for(int i=21;i>=0;--i)
	 		if(deep[parent[t][i]]>=deep[q.top()]) t=parent[t][i];
	 		if(t==q.top()||pre[t]==pre[q.top()]) q.pop();
	 		else break;
		 }
		 if(!q.empty()) puts("NO");
		 else puts("YES");
	 }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章