HDU - 5927 F - Auxiliary Set

Given a rooted tree with n vertices, some of the vertices are important. 

An auxiliary set is a set containing vertices satisfying at least one of the two conditions: 

It is an important vertex 
It is the least common ancestor of two different important vertices.

You are given a tree with n vertices (1 is the root) and q queries. 

Each query is a set of nodes which indicates the  unimportant vertices in the tree. Answer the size (i.e. number of vertices) of the auxiliary set for each query. 
InputThe first line contains only one integer T ( T1000T≤1000), which indicates the number of test cases. 

For each test case, the first line contains two integers n ( 1n1000001≤n≤100000), q ( 0q1000000≤q≤100000). 

In the following n -1 lines, the i-th line contains two integers  ui,vi(1ui,vin)ui,vi(1≤ui,vi≤n) indicating there is an edge between  uiuii and  vivi in the tree. 

In the next q lines, the i-th line first comes with an integer  mi(1mi100000)mi(1≤mi≤100000) indicating the number of vertices in the query set.Then comes with mi different integers, indicating the nodes in the query set. 

It is guaranteed that  qi=1mi100000∑i=1qmi≤100000

It is also guaranteed that the number of test cases in which  n1000n≥1000  or  qi=1mi1000∑i=1qmi≥1000 is no more than 10. 
OutputFor each test case, first output one line "Case #x:", where x is the case number (starting from 1). 

Then q lines follow, i-th line contains an integer indicating the size of the auxiliary set for each query. 
Sample Input
1
6 3
6 4
2 5
5 4
1 5
5 3
3 1 2 3
1 5
3 3 1 4
Sample Output
Case #1:
3
6
3

所有的重要节点肯定符合条件,我们先记录下来。

对于所有的非重要条件,我们需要判断。

我们按照深度进行排序,优先处理最深的。

如果这个不重要节点它没有孩子,那么它是没有利用价值的,以后什么作用都起不到,我们直接把它删掉,

也就是让他父亲节点的孩子节点个数-1.他的父亲就可以不用考虑他了。

如果他有一个孩子,那么他可能有用,可能没用。但是可以确定它自己肯定不符合条件,所以不做处理。

如果他大于等于两个孩子。我们可以百分百确定这两个孩子一定都是重要节点。这个点肯定符合条件,应该

ans++。为什么呢? 如果他的孩子不是重要节点,那么他的孩子要么有1个孩子,要么没有孩子。如果没有

孩子,那么因为它也是不重要的,童谣经历我们这个判断,在上面一步已经被删除了。如果它一个孩子,那么

那个孩子一定是重要的,为什么?同样如果不是,那也被删除了。

说白了从深处还是处理的,所以可以保证当前节点的现存的孩子节点数都是重要节点,所以只要大于等于2,

直接ans++即可。最后输出ans。

至于父亲节点,孩子节点,深度,用一个dfs就全部预处理出来了

#include <bits/stdc++.h> using namespace std; struct edge {     int to;     int next; }g[200200]; int head[100100]; int cnt; ///dfs使用 int vis[100100]; int son[100100]; int dep[100100]; int fat[100100]; / int not_important[100100]; int now_son[100100];//记录子节点个数,也就是son,因为要改动,所以用这个来代替改动 int n,m; int u,v; int k; void add_edge(int v, int u) {     g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++; } void dfs(int v,int father,int depth) {     vis[v]=1;//该点已经访问     fat[v]=father;//记录父亲节点     dep[v]=depth;//记录深度     for(int i=head[v];i!=-1;i=g[i].next)     {         int u=g[i].to;         if(!vis[u])         {             dfs(u,v,depth+1);             son[v]++;//记录孩子节点         }     } } void init() {     cnt=0;     memset(head,-1,sizeof(head));     memset(son,0,sizeof(son));     memset(vis,0,sizeof(vis)); } bool cmp(int a, int b) {     return dep[a] > dep[b]; } int main() {     int t;     scanf("%d", &t);     for(int tt=1;tt<=t;tt++)     {         init();         scanf("%d%d", &n, &m);         for(int i=1;i<n;i++)         {             scanf("%d%d", &u, &v);             add_edge(u,v);             add_edge(v,u);         }         dfs(1,-1,1);          printf("Case #%d:\n", tt);         for(int i=1;i<=m;i++)         {              scanf("%d", &k);             int ans=n-k;//现在ans等于所有重要点的个数,现在我们要判断非重要点是否符合条件             for(int j=1;j<=k;j++)             {  scanf("%d", &not_important[j]);             }             for(int j=1;j<=k;j++)             {                 now_son[not_important[j]]=son[not_important[j]];             }             sort(not_important+1,not_important+1+k,cmp);//按照深度来排序,优先处理最深的。             for(int j=1;j<=k;j++)//对于第j个不重要节点             {                 int id=not_important[j];                 if(now_son[id]>=2)//如果这个非重要节点有两个孩子,那么一定是                 {            //有人想万一那两个孩子有一个是不重要的呢。我们是从深处处理的。                             //如果他的孩子是非重要的,我们肯定先处理他的孩子,处理完,我们                             //把孩子给删掉,也就是这个节点就没有这个孩子了,也就是只有一个孩子。                     ans++;                 }                 else if(now_son[id]==0)//如果当前节点没有孩子,那么他肯定不符合条件了                 {                     //找到他的父亲节点,把父亲节点的孩子数-1.保证某个点的所有孩子全都是重要的。                      //这也是我们从深处还是处理的原因。                     now_son[fat[id]]--;                 }             }            printf("%d\n", ans);         }     } }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值