HDU 5927 Auxiliary Set (DFS+模拟)

来源:互联网 发布:淘宝店铺添加视频教程 编辑:程序博客网 时间:2024/06/05 00:43

Auxiliary Set

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


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  or qi=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

Source
2016CCPC东北地区大学生程序设计竞赛 - 重现赛

题意是给定一棵树,给出q次询问,每次给定一个集合,集合中的数为不重要的数,其他数为重要数,但是如果一个不重要数的孩子有两个及两个以上的是重要数,那么这个数也是一个重要数,问最后有多少的重要数。

显然除集合内的题都是重要数,需要确定的是集合内的数是否是重要数,然后就在搞集合内的重要数,然后就花样超时,实在是搞不懂为什么花样超时,也实在搞不懂为什么随便一交就AC,莫名AC。对于不重要数,需要判断它的孩子是否有两个以上的重要数,dfs求的当前结点的 孩子数和当前结点的父结点都可以想到,但之后有一步优化,因为每次都是输入一个集合,为了确保当前结点的后效性,需要从最后一层结点向上遍历,此时需要在dfs中记录当前结点在这棵树中的层数,然后对输入的m个点进行sort排序,让后进入树的结点排在前面,优先遍历。

遍历时需要记录当前结点的父结点,如果此结点的重要孩子数>=2,则ans++,如果此结点的重要孩子数==0,那么这个点对其父节点没有贡献,则此父结点孩子数--,因为下一次要恢复孩子数,所以用另一个数组记录减去了多少孩子,最后将这些孩子的数量再加上,最后输出n-m+ans.

代码实现:
#include <stdio.h>#include <math.h>#include <stdlib.h>#include <string.h>#include <iostream>#include <algorithm>#include <string>#include <queue>#include <stack>#include <vector>#include <set>#include <map>#define mset(a,i) memset(a,i,sizeof(a))using namespace std;typedef long long ll;const int INF=0x3f3f3f3f;const int mod=1e9+7;const int MAX=505050;const double eps=1e-6;int dir[4][2]={1,0,0,1,-1,0,0,-1};inline void SS(char*s){scanf("%s",s);}inline ll SI(){ll x;scanf("%lld",&x);return x;}inline ll P(ll x){printf("%lld\n",x);}inline ll qpow(ll n,ll m){n%=mod;ll ans=1;while(m){if(m%2)ans=(ans*n)%mod;m/=2;n=(n*n)%mod;}return ans;}inline ll inv(ll b){return b==1?1:(mod-mod/b)*inv(mod%b)%mod;}inline ll inv2(ll b){return qpow(b,mod-2);}struct node{    int s,t,next;}e[MAX];int head[MAX],cnt;void add(int u,int v){    e[cnt]=node{u,v,head[u]};    head[u]=cnt++;}int vis[MAX];int fa[MAX];int child[MAX];int a[MAX],b[MAX],c[MAX];int vf[MAX];void dfs(int root,int dad,int index){    c[root]=index;    fa[root]=dad;    child[root]=0;    for(int i=head[root];~i;i=e[i].next)    {        int t=e[i].t;        if(t!=dad)        {            child[root]++;            dfs(t,root,index+1);        }    }}int cmp(int a,int b){    return c[a]>c[b];}int main(){    int T,r=1,n,q,u,v,m;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&q);        memset(head,-1,sizeof(int)*(n+2));        cnt=0;        for(int i=1;i<n;i++)        {            scanf("%d%d",&u,&v);            add(u,v);            add(v,u);        }        printf("Case #%d:\n",r++);        memset(vis,-1,sizeof(int)*(n+2));        memset(vf,-1,sizeof(int)*(n+2));        dfs(1,-1,1);        mset(b,0);        while(q--)        {            scanf("%d",&m);            int ans=0;            for(int i=1;i<=m;i++)            scanf("%d",&a[i]);            sort(a+1,a+1+m,cmp);            for(int i=1;i<=m;i++)            {                int temp=fa[a[i]];                if(temp==-1&&child[a[i]]>=2)                ans++;                if(temp==-1)                continue;                if(child[a[i]]>=2)                ans++;                if(child[a[i]]==0)                {                    child[temp]--;                    b[temp]++;                }            }            printf("%d\n",n-m+ans);            for(int i=1;i<=m;i++)            {                int temp=fa[a[i]];                if(b[temp])                {                    child[temp]+=b[temp];                    b[temp]=0;                }            }        }    }    return 0;}