HDU 5927 Auxiliary Set By Assassin

来源:互联网 发布:js点击radio 编辑:程序博客网 时间:2024/06/05 14:12

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
u
i
,
v
i
(1≤
u
i
,
v
i
≤n)
indicating there is an edge between
u
i
i and
v
i
in the tree.

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

q
i=1
m
i
≤100000
.

It is also guaranteed that the number of test cases in which
n≥1000
or

q
i=1
m
i
≥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

这个题目本来以为时LCA,但是LCA还没学会,就被告诉xjb可以出来。。。
题意:题目大概是这样的,一颗树一种叫Auxiliary Set节点,如果满足该点是重要的或者是某两点的 least common ancestor 就满足条件。但是这个可以用类似贪心的方法做。我们首先将树建立好,用father数组和son数组分别纪录i点的父亲和孩子是谁,dep数组纪录数的层数。
那么我们如何判断一个点是否为LCA呢?只要他有至少两个子树中分别有重要点就行。那么怎么办!树状dp?NO!会超时!我们用dep层数从底层到高层排序!酱紫!

int cmp(const int &aa,const int &bb){    if(dep[aa]>dep[bb])return 1;    return 0;}

好了,每次从底层对上层的影响是什么?如果时叶子结点,son[i]==0,那么son[father[i]]就减一!如果father这个点值还是不小与2!可以了!
当然,这里我们还需要!注意!这里每次赋值要每次直接用输入的值,专业点处离散化

#include<bits/stdc++.h>#define input freopen("input.txt","r",stdin)using namespace std;vector<int>s[100005];int father[100005],son[100005],a[100005],dep[100005],cha[100005];void dfs(int u,int pa) {    father[u]=pa;    dep[u]=dep[pa]+1;    son[u]=0;    for(int i=0; i<s[u].size(); i++)        if(s[u][i]!=pa) {            dfs(s[u][i],u);            son[u]++;        }}int cmp(const int &aa,const int &bb){    if(dep[aa]>dep[bb])return 1;    return 0;}int main(){    input;    int i,j;    int q,n,m,tmp1,tmp2;    int t,time=1;    scanf("%d",&t);        while(t--)        {            scanf("%d%d",&n,&q);            for(i=0;i<=n;i++) s[i].clear();            for(i=1;i<n;i++)            {                scanf("%d%d",&tmp1,&tmp2);                s[tmp1].push_back(tmp2);                s[tmp2].push_back(tmp1);            }               dfs(1,0);//          for(i=1;i<=n;i++)cout<<son[i]<<" ";cout<<endl;            printf("Case #%d:\n",time++);            while(q--)            {                scanf("%d",&m);                int ans=n-m;                for(i=1;i<=m;i++)  scanf("%d",&a[i]);                for(i=1;i<=m;i++)  cha[a[i]]=son[a[i]];                sort(a+1,a+1+m,cmp);                for(i=1;i<=m;i++)                {                    if(cha[a[i]]>=2)ans++;                    else if(cha[a[i]]==0) cha[father[a[i]]]--;                }                cout<<ans<<endl;            }        }    return 0;}

PS:其实时借鉴大牛思路!感谢!

0 0