hdu 5927 Auxiliary Set dfs+逆向思维

来源:互联网 发布:农业大数据价值 编辑:程序博客网 时间:2024/05/17 01:39

Auxiliary Set

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1956    Accepted Submission(s): 568


Problem Description
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.
 

Input
The first line contains only one integer T (T1000), which indicates the number of test cases.

For each test case, the first line contains two integers n (1n100000), q (0q100000).

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

In the next q lines, the i-th line first comes with an integer mi(1mi100000) 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.

It is also guaranteed that the number of test cases in which n1000  orqi=1mi1000 is no more than 10.
 

Output
For 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
16 36 42 55 41 55 33 1 2 31 53 3 1 4
 

Sample Output
Case #1:363
Hint

For the query {1,2, 3}:•node 4, 5, 6 are important nodes For the query {5}:•node 1,2, 3, 4, 6 are important nodes•node 5 is the lea of node 4 and node 3 For the query {3, 1,4}:• node 2, 5, 6 are important nodes

解: 题意不多说 说一下思路;
先来遍dfs,记录每个结点的儿子数目,父节点,与深度;
对于给定的不重要的点,先算出重要的点的个数,最后的结果一定>=这个数,再把不重要的点按照深度优先排完序后,从第一个开始做这样的处理:① 如果该点没儿子,则该点一定不满足题意
                                                                                                                            ② 该点有一个儿子,则此儿子一定是重要的点,因为不重要的点在①中已经删除;不作处理,考虑到此点的儿子可能对此点的父辈做出贡献;
                                                                                                                            ③该点有两个儿子,两个儿子一定经过①②的严格筛选,一定满足题意,++;
下面是代码:注意while(m--)里的代码,每一次某个点的儿子数减之后,最后要补回来;如果不补,用其他的做法,会超时!!!
#include <iostream>#include <string.h>#include <string>#include <algorithm>using namespace std;const int maxn=2e5+10;const int maxx=1e5+10;struct point {int next;int to;};struct poin{int deep;int father;int son;int nu;};point pt[maxn];poin p[maxn],pp[maxn],ppp[maxn];int head[maxn];bool vis[maxx],vis2[maxx];int dis[maxx],sto[maxx];int n,m,q;bool cmp(poin a,poin b){return a.deep>b.deep;}void add(int u,int v){pt[q].next=head[u];pt[q].to=v;head[u]=q++;}void dfs(int st){for (int i=head[st];i!=-1;i=pt[i].next){int v=pt[i].to;if (!vis[v]){ vis[v]=true; p[v].deep=p[st].deep+1; p[st].son++;  dfs(v); p[v].father=st;    }}}void init(){memset(vis,false,sizeof(vis));memset(head,-1,sizeof(head));memset(p,0,sizeof(p));p[1].deep=0;p[1].father=-1;vis[1]=true;q=1;}int main(){int u,v,t,ans,vv,k,cnt=1;;cin>>t;while (t--){scanf("%d%d",&n,&m);int nu=n-1;init();while (nu--){scanf("%d%d",&u,&v);add(u,v);add(v,u);}dfs(1);printf("Case #%d:\n",cnt++);while (m--){  scanf("%d",&vv);  ans=0;  k=0;  for (int i=1;i<=vv;i++)  {scanf("%d",&nu);    pp[k].nu=nu;    pp[k].deep=p[nu].deep;    pp[k++].father=p[nu].father;  }  int s=n-vv;  sort(pp,pp+k,cmp);  for (int i=0;i<k;i++)  {if (p[pp[i].nu].son>=2)ans++;if (p[pp[i].nu].son==0) {p[p[pp[i].nu].father].son-=1;sto[i]++;         }  }  for (int i=0;i<k;i++)  if (sto[i]!=0)  {  p[p[pp[i].nu].father].son+=sto[i]; //补一器,sto[i]不为0,就是1;  sto[i]--; //补完接着清空;  }  printf("%d\n",ans+s);    }}return 0;} 


原创粉丝点击