hdu-5927 Auxiliary Set
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 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.
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.这个节点被标记为重点。2.这个节点是两个重点的LCA。
现在给出q此查询,每次查询时给出的是没有被标记的节点的编号,你要输出集合的大小。
思路:
这个题做LCA显然不现实。现在,从最深的没有标记的点进行检查,要是这个点在集合里,那么它的必定有两个孩子节点(因为此时他的深度是最大的)。要是只有一个孩子节点的话,那么至少从它的这个孩子节点出发的LCA不是它,这种情况下要保留它,利用它判断它的祖先是否在集合中(同理,要是它有两个孩子节点也要保留)。要是它的孩子节点数是0,那么这个点对于祖先的贡献肯定是没有了,就删掉。
#include "bits/stdc++.h" using namespace std; const int maxn = 100000 + 100; struct Edge { int next, to; }da[maxn*2]; int tot; int par[maxn]; int son[maxn]; int dep[maxn]; int head[maxn]; int a[maxn], t[maxn]; int N, q; void add_edge(int u, int v) { da[tot].to = v; da[tot].next = head[u]; head[u] = tot++; } void dfs(int u, int fa, int d) { dep[u] = d; par[u] = fa; for (int i = head[u]; i != -1; i = da[i].next) { int v = da[i].to; if (v != fa) dfs(v, u, d + 1), son[u]++; } } bool cmp(int x, int y){return dep[x]>dep[y];} int main(int argc, char const *argv[]) { int T; scanf("%d", &T); int Kcase = 0; while (T--) { memset(son, 0, sizeof(son)); memset(head, -1, sizeof(head)); scanf("%d%d", &N, &q); tot = 0; for (int i = 1; i <= N - 1; i++) { int u, v; scanf("%d%d", &u, &v); add_edge(u, v); add_edge(v, u); } dfs(1, -1, 1); printf("Case #%d:\n", ++Kcase); while (q--) { int k; scanf("%d", &k); for (int i = 1; i <= k; i++) scanf("%d", a + i); for (int i = 1; i <= k; i++) t[a[i]] = son[a[i]]; sort(a+1, a+1+k, cmp); int ans = N - k; for (int i = 1; i <= k; i++) { if (t[a[i]] >= 2) ans++; else if (t[a[i]] == 0) t[par[a[i]]]--; } printf("%d\n", ans); } } return 0; }