先预处理出每个节点的父节点,子节点个数,深度
当一个不重要节点有两个或以上子节点,并且有两个或以上子树里有重要点,那么它也会变为重要点
对于每次询问先把不重要点按深度排序,然后按顺序看其是否满足以上条件
需要加一个数组保存节点有多少子树有重要点
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
struct Edge
{
int to, nxt;
} edge[2 * N];
int tot, tot0;
int first[N], first0[N];
void addedge(int u, int v)
{
edge[tot].to = v;
edge[tot].nxt = first[u];
first[u] = tot++;
}
int deep[N], f[N], son[N];
void init(int u, int d, int fa)
{
deep[u] = d;
son[u] = 0;
f[u] = fa;
for (int i = first[u]; i != -1; i = edge[i].nxt)
{
int v = edge[i].to;
if (v != fa)
{
init(v, d + 1, u);
son[u]++;
}
}
}
bool cmp(int a, int b)
{
return deep[a] > deep[b];
}
int vv[N];
int num[N];
int ans;
int main()
{
int T, kase = 0;
scanf("%d", &T);
while (T--)
{
int n, q;
scanf("%d%d", &n, &q);
int a, b;
tot = 0;
memset(first, -1, sizeof(int) * (n + 1));
for (int i = 0; i < n - 1; i++)
{
scanf("%d%d", &a, &b);
addedge(a, b);
addedge(b, a);
}
printf("Case #%d:\n", ++kase);
if (!q)
continue;
init(1, 0, 1);
int m;
memset(vv, 0, sizeof(int) * (n + 1));
while (q--)
{
scanf("%d", &m);
for (int i = 0; i < m; i++)
{
scanf("%d", &num[i]);
vv[num[i]] = 0;
}
sort(num, num + m, cmp);
ans = n - m;
for (int i = 0; i < m; i++)
{
if (son[num[i]] - vv[num[i]] >= 2)
ans++;
else if (son[num[i]] - vv[num[i]] == 0)
vv[f[num[i]]]++;
}
printf("%d\n", ans);
}
}
return 0;
}