思路分析
题意:让我们树上找一条链,使得所有点都在链上,或者距这条链上一点的距离为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;
}