hdu 5927 DFS



链接:戳这里


Auxiliary Set
Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other


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 (T≤1000), which indicates the number of test cases.

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

In the following n -1 lines, the i-th line contains two integers ui,vi(1≤ui,vi≤n) 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(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=1mi≤100000.

It is also guaranteed that the number of test cases in which n≥1000  or ∑qi=1mi≥1000 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

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
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


题意:

根节点为1的树,定义一个节点为重要的节点至少满足两个条件中的一个条件

1:自己本身是重要的点

2:这个点不是重要的点,但是是两个重要节点的最近公共祖先

q组询问给出m个不重要的点
输出树上有多少重要的点

思路:
对于每组询问m个不重要的节点,按深度从大到小排序,然后去看每个节点造成的影响
对于当前的不重要的点,如果不存在儿子是重要的点,那么父亲肯定是要重要的点的个数-1的
如果存在一个儿子是重要的点,那么祖先能否从另外一条链上取一个重要的点来相结合,所以不处理
如果存在>=2个儿子满足是重要的点,肯定是ans++的

代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<list>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define Max 1e9
using namespace std;
int T;
int n,m,q;
struct edge{
    int v,next;
}e[400100];
int head[400100],tot,son[200100],sz2[200100],deep[200100],a[200100];
int fa[200100];
int change[200100],change2[200100];
void init(){
    tot=1;
    mst(head,-1);
    for(int i=0;i<=n;i++) {
        son[i]=0;
        deep[i]=0;
        fa[i]=-1;
        change[i]=0;
        sz2[i]=0;
        change2[i]=0;
    }
}
void Add(int u,int v){
    e[tot].v=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
void DFS(int u,int Fa,int dep){
    deep[u]=dep;
    for(int i=head[u];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(v==Fa) continue;
        fa[v]=u;
        DFS(v,u,dep+1);
        son[u]++;
    }
}

bool cmp(int x,int y){
    return deep[x]>deep[y];
}

int main(){
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        scanf("%d%d",&n,&q);
        init();
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            Add(u,v);
            Add(v,u);
        }
        fa[1]=0;
        son[0] = 1;
        DFS(1,0,1);
        printf("Case #%d:\n",cas);
        while(q--){
            scanf("%d",&m);
            for(int i=1;i<=m;i++) scanf("%d",&a[i]);
            sort(a+1,a+m+1,cmp);
            int ans=0;
            for(int i=1;i<=m;i++){
                if(son[a[i]] == 0) {
                    son[fa[a[i]]]--;
                    change[fa[a[i]]]++;
                }
                if(son[a[i]] >= 2) {
                    ans++;
                    continue;
                }
            }
            printf("%d\n",n-m+ans);
            for(int i = 1; i <= m; ++i) {
                if(change[fa[a[i]]]) {
                    son[fa[a[i]]] += change[fa[a[i]]];
                    change[fa[a[i]]] = 0;
                }
            }
        }
    }
    return 0;
}
/*
10
7 10
1 5
2 5
3 5
4 5
4 6
1 7
1 7
2 1 7
3 1 2 3
1 5
3 3 1 4
*/




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值