看了题解才会... 之前还一直想用LCA怎么搞...
对于一个非重要点 只要其下至少两颗子树上分别有两个重要点 那这个非重要点一定是他们的LCA 也变成了重要节点
dfs一遍 记录每个节点的直接孩子有几个 记为son[cur] 对于每一个查询 把点按深度从深到浅排序 然后扫一遍
如果当前点的son[cur]==0 那么以当前点为根的子树上已经不存在重要点 其父节点也就少了一个提供重要点的来源 son[fa[cur]]--
如果当前点的son[cur]==1 对自己对父节点都没啥影响 忽略
如果当前点的son[cur]==2 那么他也会被记为重要点
#include <bits/stdc++.h> using namespace std; struct node1 { int v; int next; }; node1 edge[200010]; int first[100010],fa[100010],son[100010],deep[100010]; int n,num; bool cmp(int u,int v) { return deep[u]>deep[v]; } void addedge(int u,int v) { edge[num].v=v; edge[num].next=first[u]; first[u]=num++; return; } void dfs(int cur,int dep) { int i,v; son[cur]=0,deep[cur]=dep; for(i=first[cur];i!=-1;i=edge[i].next) { v=edge[i].v; if(v!=fa[cur]) { fa[v]=cur,son[cur]++; dfs(v,dep+1); } } return; } int main() { int tem[100010],pre[100010]; int t,cas,q,k,i,u,v,ans; scanf("%d",&t); for(cas=1;cas<=t;cas++) { scanf("%d%d",&n,&q); memset(first,-1,sizeof(first)); num=0; for(i=1;i<=n-1;i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } fa[1]=-1; dfs(1,1); printf("Case #%d:\n",cas); while(q--) { scanf("%d",&k); for(i=1;i<=k;i++) { scanf("%d",&pre[i]); tem[pre[i]]=son[pre[i]]; } sort(pre+1,pre+k+1,cmp); ans=n-k; for(i=1;i<=k;i++) { if(tem[pre[i]]>=2) ans++; else if(tem[pre[i]]==0) tem[fa[pre[i]]]--; } printf("%d\n",ans); } } return 0; }
如果当前点的son[cur]==1