CF-div3-629-E - Tree Queries

思路分析

题意:让我们树上找一条链,使得所有点都在链上,或者距这条链上一点的距离为1;
分析:
1.假如这个点到链上的距离为1,说明这个点的父亲在链上。
2.首先想到思考如何去找这条链,就是去选另一个端点。肯定是从根出发到深度最深的点的这条链,因为端点deep越深,这条链能覆盖到的点越多嘛。
3.接着只要判其它结点或者父亲与这个点是不是在一条链上就可以了。判是不是在一条链,只要判断lca(当前结点,最深结点) 是不是 = 当前结点 或者 当前结点的父亲。

做法:树链剖分求出lca,father,deep,然后找到最深点,判断其它点与它的lca是否满足条件即可。

代码

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

const int maxn = 2e5+100;
vector<int> g[maxn];
int fa[maxn],depth[maxn],sz[maxn],son[maxn],id[maxn],rk[maxn],top[maxn],bot[maxn];
int cnt = 0;
int root;

void dfs(int x,int deep){
	depth[x] = deep;
	sz[x] = 1;
	for(int li = 0;li<g[x].size();li++){
		int i = g[x][li];
		if(i == fa[x]) continue;
		fa[i] = x;
		dfs(i,deep+1);
		sz[x] += sz[i];
		if(sz[i] > sz[son[x]]) son[x] = i;
	}
}

void dfs2(int x,int tp){
	top[x] = tp;
	id[x] = ++cnt;
	rk[cnt] = x;
	if(son[x]) dfs2(son[x],tp),bot[x] = bot[son[x]];
	else bot[x] = x;
	for(int li=0;li<g[x].size();li++){
		int i = g[x][li];
		if(i != fa[x] && i != son[x])
			dfs2(i,i);
	}
}

int lca(int u,int v){
	while(top[u] != top[v]){
		if(depth[top[u]] < depth[top[v]]) swap(u,v);
		u = fa[top[u]];
	}
	if(depth[u] < depth[v]) return u;
	return v;
}

int node[maxn];
void solve(){
	int k;
	cin>>k;
	int maxDeep = 0,maxNode;
	for(int i=1;i<=k;i++) {
		cin>>node[i];
		if(maxDeep <= depth[node[i]]){
			maxDeep = depth[node[i]];
			maxNode = node[i];
		}
	}
	for(int i=1;i<=k;i++){
		if(node[i] == maxNode) continue;
		int LCA = lca(maxNode,node[i]);
		if(!(LCA == node[i] || LCA == fa[node[i]])){
			puts("NO");
			return;
		}
	}
	puts("YES");
}

int main(){
	ios::sync_with_stdio(false);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	root = 1;
	dfs(root,1);
	dfs2(root,root);
	while(m--){
		solve();
	}
	return 0;
}
posted @ 2020-03-27 12:52  fishers  阅读(228)  评论(2编辑  收藏  举报