HDU_5927 Auxiliary Set(DFS+思路)

Auxiliary Set

Time Limit: 9000/4500 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
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=1qmi100000.

It is also guaranteed that the number of test cases in which n ≥ 1000 n≥1000 n1000 or ∑ i = 1 q m i ≤ 1000 \sum_{i=1}^qm_i≤1000 i=1qmi1000 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=nm。将所有非重要点按深度降序排列,并依次访问,如果当前节点的度数大于等于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];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值