给你一个树和几个不重要的点,求重要的点和是至少两个重要点的最近公共祖先的点的个数。
先预处理出每个点的儿子个数,和每个节点的父节点。
每次询问把不重要点的构图(只需要遍历每个不重要点的子代,找到是否有要重要即可),如果不重要点是两个以上的重要点的最近公共祖先,那么就答案+1,最后加上重要点的个数,即为答案。
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int N=100005;
int n,m,head[N],num[N],pre[N],a[N],e[N*2][2],cnt;
vector<int> q[N];
void add(int u,int v)
{
e[++cnt][0]=u;
e[cnt][1]=head[v];
head[v]=cnt;
e[++cnt][0]=v;
e[cnt][1]=head[u];
head[u]=cnt;
}
void dfs(int u,int fa)
{
for(int i=head[u]; ~i; i=e[i][1])
if(e[i][0]!=fa)
num[u]++,pre[e[i][0]]=u,dfs(e[i][0],u);
}
int dd(int x)
{
int aa=0,cn=q[x].size();
for(int i=0;i<cn;i++)
if(dd(q[x][i])>=1)
aa++;
return num[x]-cn+aa;
}
int main()
{
int T,u,v;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
printf("Case #%d:\n",cas);
cnt=0;
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1; i<n; i++)
scanf("%d%d",&u,&v),add(u,v);
dfs(1,0);
while(m--)
{
int t,ans;
scanf("%d",&t);
ans=n-t;
for(int i=0; i<t; i++)
scanf("%d",&a[i]),q[a[i]].clear();
for(int i=0;i<t;i++)
q[pre[a[i]]].push_back(a[i]);
for(int i=0; i<t; i++)
ans+=(dd(a[i])>=2);
printf("%d\n",ans);
}
memset(num,0,sizeof(num));
}
}