Auxiliary Set
Time Limit: 9000/4500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 964 Accepted Submission(s): 302
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.
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 ui i 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.
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 ui i 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.
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 3HintFor 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
题目大意:
给出 整棵树。给出 k 个点, 这 k 个点是不重要的点。
需要求的是一个集合的大小,满足下面两个条件可以放入这个集合中
1. 重要的点
2. 如果某个不重要点有两个儿子为 重要的点 ,那么也放入这个集合中。
输出 集合的大小。
思路:
dfs 处理好每个点有多少个儿子。
然后对于所有不重要的点,按照深度进行从大到小排序。
从深度最大的开始检索。如果当前节点的儿子数量大于 等于2 那么当前点可以放入集合中。
如果当前点 没有儿子 那么我们可以暂时删掉这个点(将其父亲 的儿子节点的数量减 1)(如果他的父节点有两个儿子,一个为重要的,一个为不重要的,并且这个不重要的
节点没有儿子节点了 那么这个父亲节点是不重要的点,虽然他有两个儿子,但是他只有一个重要的儿子)
检索完就可以了
AC代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,q;
int head[200005];
int tot;
int nextt[200005];
int num[200005];
int ff[100005];
int son[100005];
int tt[100005];
int eenum[100005];
struct node
{
int a;
int dep;
friend bool operator < (const node &aa,const node &b)
{
return aa.dep>b.dep;
}
}haha[100005];
bool cmp(int x,int y)
{
return haha[x].dep>haha[y].dep;
}
void add(int u,int v)
{
num[tot]=u;
nextt[tot]=head[v];
head[v]=tot;
tot++;
num[tot]=v;
nextt[tot]=head[u];
head[u]=tot;
tot++;
}
void dfs(int u,int f)
{
ff[u]=f;
haha[u].dep=haha[f].dep+1;
son[u]=0;
int t;
for(t=head[u];t!=-1;t=nextt[t])
{
if(num[t]!=f)
{
dfs(num[t],u);
son[u]++;
}
}
}
int main()
{
int T;
int ca=1;
scanf("%d",&T);
int a,b;
while(T--)
{
scanf("%d%d",&n,&m);
tot=0;
for(int i=0;i<=n;i++)
{
head[i]=-1;
}
haha[0].dep=0;
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&a,&b);
add(a,b);
}
dfs(1,0);
int ans;
printf("Case #%d:\n", ca);
ca++;
while(m--)
{
scanf("%d",&q);
ans=n-q;
for(int i=0;i<q;i++)
{
scanf("%d",&eenum[i]);
}
sort(eenum,eenum+q,cmp);
for(int i=0;i<q;i++)
{
tt[eenum[i]]=son[eenum[i]];
}
for(int i=0;i<q;i++)
{
if(tt[eenum[i]]>=2)
{
ans++;
}
else if(tt[eenum[i]]==0)
{
tt[ff[eenum[i]]]--;
}
}
cout<<ans<<endl;
}
}
}