1328E - Tree Queries题解

做了这场的最后两题明显感觉比上一场的div3难啊。
题意:给一棵树,每次查询包含若干个点,问是否从根存在一条路径,是每个点或在这条路径上,或离路径上的点最近距离为1。
通过画图比划不难发现,一个点如果满足如上条件,则它的父亲一定在路径上,因为树结构的特殊性,如果某结点的儿子在路径中,则此节点一定也在路径中。
对于同一深度的所有节点,最多只有一个结点在路径上。所以,我们先将k个结点按照深度排序,进行遍历,求出每两个点x,y的最近公共祖先,如果它们的LCA是x,说明x在路径上,且可以延伸到y的父亲。如果它们的LCA是fa[x],说明经过了fa[x],x此时已满足条件,并将路径延伸到fa[y]。至于y和后面会不会有冲突,需要在下一次求的时候在判断。
总复杂度(O(KlogK+KlogN));
使链向星存树。
PS:如果不知道LCA是什么,可去luogu上找模板题学。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<vector>
using namespace std;
struct zzz {
	int t, nex;
} e[300010 << 1];
int head[200010], tot;
void add(int x, int y) {
	e[++tot].t = y;
	e[tot].nex = head[x];
	head[x] = tot;
}
int times=0;
int dfn[200010];
int depth[500001], fa[500001][26], lg[500001];
void dfs(int now, int fath) {
	fa[now][0] = fath;
	depth[now] = depth[fath] + 1;
	for(int i = 1; i <= lg[depth[now]]; ++i)
		fa[now][i] = fa[fa[now][i-1]][i-1];
	for(int i = head[now]; i; i = e[i].nex)
		if(e[i].t != fath) dfs(e[i].t, now);
}
int LCA(int x, int y) 
{
	if(depth[x] < depth[y]) swap(x, y);
	while(depth[x] > depth[y])
		x = fa[x][lg[depth[x]-depth[y]] - 1];
	if(x == y) return x;
	for(int k = lg[depth[x]] - 1; k >= 0; --k)
		if(fa[x][k] != fa[y][k])
			x = fa[x][k], y = fa[y][k];
	return fa[x][0];
}
int k;
int save[200010];
int fl=1;
int x, y;
struct node {
	int d;
	int index;
} tree[200010];
 
bool cmp(node x,node y) {
	return x.d<y.d;
}
int n, m;
int main() {
	scanf("%d%d", &n, &m );
	for(int i = 1; i <= n-1; ++i) {
		scanf("%d%d", &x, &y);
		add(x, y);
		add(y, x);
	}
	for(int i = 1; i <= n; ++i)
		lg[i] = lg[i-1] + (1 << lg[i-1] == i);
	dfs(1, 0);
for(int j = 1; j <= m; ++j) 
		{
			fl=1;
			scanf("%d",&k);
			for(int i=1; i<=k; i++) 
			{
				scanf("%d",&save[i]);
			tree[i].index=save[i];
				tree[i].d=depth[tree[i].index];
			}
			sort(tree+1,tree+k+1,cmp);
		
			for(int i=2; i<=k; i++)
			 {
				x=tree[i-1].index;
				y=tree[i].index;
				if (x==1) {
					continue;
				}
					if (LCA(y,x)!=x&&LCA(y,x)!=fa[x][0]) 
					{
						fl=0;
					}
			}
			if (fl) {
				printf("YES\n");
			} else {
				printf("NO\n");
			}
		}
	return 0;
}

后来发现别人有O(K)的做法,是用dfs序做的。
不得不说自己还是太菜了。
有问题可以在下面评论。如果对你有帮助,点个赞再走幺。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值