アイデア解析
質問の意味:このチェーンの点からチェーン内のすべてのポイント、または距離が1であるように、私たちはチェーンの木を見つけてみましょう;
分析:
1.チェーン1には、この時点での距離場合は、ポイントを説明チェーンの父。
2.最初に考えたのは深い終わり深く、より多くのこのチェーンがポイントの事をカバーすることができるので、確かにこのチェーンの深さの最深点までのルートから、このチェーンを見つける方法を考えること。
3.次に限り父親または他のノードは、この点に判断されるように、それの一方の鎖上に存在しません。判定は、現在のノードまたは父親でない限り、LCAの決意(現在のノード、最も深いノード)=現在のノードとして、連鎖していません。
方法:スプリットツリーチェーン得LCA、父、深く、そして最深点を見つけ、他の点は、それが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;
}