Auxiliary Set
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 ui 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 ∑ i = 1 q m i ≤ 100000 \sum_{i=1}^qm_i≤100000 ∑i=1qmi≤100000.
It is also guaranteed that the number of test cases in which n ≥ 1000 n≥1000 n≥1000 or ∑ i = 1 q m i ≤ 1000 \sum_{i=1}^qm_i≤1000 ∑i=1qmi≤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
题意
有一棵以1节点为根节点的有根树,树上的点分为重要点和非重要点,现在有一个集合,集合中的点,满足以下之一即可:
- 节点本身是重要点,
- 节点是两个重要点的LCA
给出树上的非重要节点,求辅助集合的大小。
题解:
因为每个询问给出的是m个非重要点,那么n-m个重要点肯定在集合中,关键在于是两个重要点LCA的非重要点。一个非重要点,需要保证所有的儿子中,至少有两个他的儿子及其所在树存在重要点。
在处理每个询问时,一个节点为非重要点,如果他的度数大于等于2,显然他是集合中的元素,如果他的度数为0,则说明他的所有儿子节点及其后代节点都是非重要点,那么对于他的父节点来说,这个儿子节点的存在无贡献,可以将其父节点的度数减一。因为会对前面有影响,所以需要先处理较深的节点。
综上,对于每棵树,需要求出每个节点的深度,其父节点,和度数(儿子的数量)。对于每次询问,暂且记 a n s = n − m ans = n-m ans=n−m。将所有非重要点按深度降序排列,并依次访问,如果当前节点的度数大于等于2,则 a n s + + ans++ ans++,如果度数等于0,则其父节点度数减1。最后输出即可。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<map>
#include<queue>
#include<stack>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 100100;
int a[maxn], dep[maxn], fa[maxn], son[maxn];
vector<int> g[maxn];
void dfs(int u, int dept);
bool cmp(int a, int b);
int main()
{
int t, q, n, m, ans, i, j, k;
scanf("%d", &t);
for(int z=1;z<=t;z++)
{
scanf("%d %d", &n, &q);
for(i=0;i<=n;i++)g[i].clear();
for(i=1;i<n;i++){
scanf("%d %d", &j, &k);
g[k].push_back(j);
g[j].push_back(k);
}
fa[1] = 0;
dfs(1, 1);
printf("Case #%d:\n", z);
while(q--)
{
scanf("%d", &m);
ans = n-m;
for(i=0;i<m;i++)
scanf("%d", &a[i]);
sort(a, a+m, cmp);
for(i=0;i<m;i++)
if(son[a[i]] == 0)
son[fa[a[i]]]--;
else if(son[a[i]]>1)
ans++;
for(i=m-1;i>=0;i--)
if(son[a[i]] == 0)
son[fa[a[i]]]++;
printf("%d\n", ans);
}
}
return 0;
}
void dfs(int u, int dept)
{
dep[u] = dept;
son[u] = 0;
for(int i=0;i<g[u].size();i++){
if(g[u][i] != fa[u]){
fa[g[u][i]] = u;
son[u]++;
dfs(g[u][i], dept+1);
}
}
}
bool cmp(int a, int b)
{
return dep[a] > dep[b];
}