1.题目链接。题目大意就是给了一棵树,这棵树上的节点有两种类别,一种是重要的点,一种是不重要的点。然后现在有一个集合,这个集合里面的节点满足两条性质中的任意一条即可:(1)这个节点是一个重要的节点.(2)这个节点不是一个重要的节点,但是这个节点是两个重要节点的LCA。然后是m组询问,每组询问首先给出一个数t,然后给出t个点,这t个点是不重要的节点,对于每组询问,输出一下这个集合的大小(也就是元素的数量)。
2分析一下可以知道,我们这个问题的主要矛盾就是在解决那些不重要的点中,有多少个是两个重要点的LCA。然后把重要的点加上去就是答案了。对于LCA我们知道,一个节点是他不同子树的LCA。然后我们只需要知道这个节点中儿子中重要节点的数量,如果这个数量大于等于2.那么这个节点就会被加入集合中,如果这个节点没有儿子,那么他对他的父亲贡献是0,所以父亲的儿子节点数减一。然后做法就比较明显了,我们一遍dfs,记录这样三个信息:当前节点的层数,节点儿子个数,节点的父亲。然后按照最底层从下向上更新即可。复杂度m*logm.
using namespace std;
const int N = 1e5 + 100;
vector<int>vec[N];
int dep[N];
int fa[N];
int cnt[N];
int vis[N];
int son[N];
struct node
{
  int x, d;
}no[N];
void dfs(int x, int y, int depth)
{
  fa[x] = y;
  dep[x] = depth;
  vis[x] = 1;
  for (int i = 0; i < vec[x].size(); i++)
  {
    if (vis[vec[x][i]])continue;
    cnt[x]++;
    dfs(vec[x][i], x, depth + 1);
  }
}
int cmp(node a, node b)
{
  return a.d > b.d;
}
int main()
{
  int n, m;
  int T;
  scanf("%d", &T);
  for (int ca = 1; ca <= T; ca++)
  {
    scanf("%d%d", &n, &m);
    memset(vis, 0, sizeof(vis));
    memset(cnt, 0, sizeof(cnt));
    for (int i = 0; i <= n; i++)vec[i].clear();
    for (int i = 1; i <n; i++)
    {
      int u, v;
      scanf("%d%d", &u, &v);
      vec[u].push_back(v);
      vec[v].push_back(u);
    }
    dfs(1, 0, 1);
    printf("Case #%d:\n", ca);
    while (m--)
    {
      int t;
      scanf("%d", &t);
      int ans = n - t;
      for (int j = 0; j < t; j++)
      {
        int x;
        scanf("%d", &x);
        no[j].x = x;
        no[j].d = dep[x];
        son[x] = cnt[x];
      }
      sort(no, no + t, cmp);
      for (int k = 0; k < t; k++)
      {
        if (son[no[k].x] >= 2)ans++;
        else if (son[no[k].x] == 0)son[fa[no[k].x]]--;
      }
      printf("%d\n", ans);
    }
  }
  return 0;
}
                










