先决条件: DFS、树、DSU
给定一棵树,其中包含从值1 到 N和E边的N 个节点,以及表示与每个节点关联的编号的数组arr[] 。您还将获得Q查询,其中包含 2 个整数{V, F} 。对于每个查询,都有一个带有顶点V的子树,任务是检查是否存在与该子树中的每个节点关联的数字计数是否为F。如果是,则打印True否则打印False 。
例子:
Input: N = 8, E = { {1, 2}, {1, 3}, {2, 4}, {2, 5}, {5, 8}, {5, 6}, {6, 7} }, arr[] = { 11, 2, 7, 1, -3, -1, -1, -3 }, Q = 3, queries[] = { {2, 3}, {5, 2}, {7, 1} }
Output:
False
True
True
Explanation:
Query 1: No number occurs three times in sub-tree 2
Query 2: Number -1 and -3 occurs 2 times in sub-tree 5
Query 3: Number -1 occurs once in sub-tree 7
Input: N = 11, E = { {1, 2}, {1, 3}, {2, 4}, {2, 5}, {4, 9}, {4, 8}, {3, 6}, {3, 7}, {4, 10}, {5, 11} }, arr[] = { 2, -1, -12, -1, 6, 14, 7, -1, -2, 13, 12 }, Q = 2, queries[] = { {2, 2}, {4, 2} }
Output:
False
True
Explanation:
Query 1: No number occurs exactly 2 times in sub-tree 2
Query 2: Number -1 occurs twice in sub-tree 4
朴素方法:想法是使用 DFS 遍历来遍历树,并计算与子树V 的每个顶点关联的数字的频率,并将结果存储在哈希图中。遍历之后,我们只需要遍历hashmap来检查给定的频率数是否存在。
下面是上述方法的实现:
Java
// Java program for the above approach
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("unchecked")
public class Main {
// To store edges of tree
static ArrayList adj[];
// To store number associated
// with vertex
static int num[];
// To store frequency of number
static HashMap freq;
// Function to add edges in tree
static void add(int u, int v)
{
adj[u].add(v);
adj[v].add(u);
}
// Function returns boolean value
// representing is there any number
// present in subtree qv having
// frequency qc
static boolean query(int qv, int qc)
{
freq = new HashMap<>();
// Start from root
int v = 1;
// DFS Call
if (qv == v) {
dfs(v, 0, true, qv);
}
else
dfs(v, 0, false, qv);
// Check for frequency
for (int fq : freq.values()) {
if (fq == qc)
return true;
}
return false;
}
// Function to implement DFS
static void dfs(int v, int p,
boolean isQV, int qv)
{
if (isQV) {
// If we are on subtree qv,
// then increment freq of
// num[v] in freq
freq.put(num[v],
freq.getOrDefault(num[v], 0) + 1);
}
// Recursive DFS Call for
// adjacency list of node u
for (int u : adj[v]) {
if (p != u) {
if (qv == u) {
dfs(u, v, true, qv);
}
else
dfs(u, v, isQV, qv);
}
}
}
// Driver Code
public static void main(String[] args)
{
// Given Nodes
int n = 8;
adj = new ArrayList[n + 1];
for (int i = 1; i <= n; i++)
adj[i] = new ArrayList<>();
// Given edges of tree
// (root=1)
add(1, 2);
add(1, 3);
add(2, 4);
add(2, 5);
add(5, 8);
add(5, 6);
add(6, 7);
// Number assigned to each vertex
num = new int[] { -1, 11, 2, 7, 1, -3, -1, -1, -3 };
// Total number of queries
int q = 3;
// Function Call to find each query
System.out.println(query(2, 3));
System.out.println(query(5, 2));
System.out.println(query(7, 1));
}
}
Java
// Java program for the above approach
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@SuppressWarnings("unchecked")
public class Main {
// To store edges
static ArrayList adj[];
// num[v] = number assigned
// to vertex v
static int num[];
// map[v].get(c) = total vertices
// in subtree v having number c
static Map map[];
// size[v]=size of subtree v
static int size[];
static HashMap ans;
static ArrayList qv[];
// Function to add edges
static void add(int u, int v)
{
adj[u].add(v);
adj[v].add(u);
}
// Function to find subtree size
// of every vertex using dfsSize()
static void dfsSize(int v, int p)
{
size[v]++;
// Traverse dfsSize recursively
for (int u : adj[v]) {
if (p != u) {
dfsSize(u, v);
size[v] += size[u];
}
}
}
// Function to implement DFS Traversal
static void dfs(int v, int p)
{
int mx = -1, bigU = -1;
// Find adjacent vertex with
// maximum size
for (int u : adj[v]) {
if (u != p) {
dfs(u, v);
if (size[u] > mx) {
mx = size[u];
bigU = u;
}
}
}
if (bigU != -1) {
// Passing referencing
map[v] = map[bigU];
}
else {
// If no adjacent vertex
// present initialize map[v]
map[v] = new HashMap();
}
// Update frequency of current number
map[v].put(num[v],
map[v].getOrDefault(num[v], 0) + 1);
// Add all adjacent vertices
// maps to map[v]
for (int u : adj[v]) {
if (u != bigU && u != p) {
for (Entry
pair : map[u].entrySet()) {
map[v].put(
pair.getKey(),
pair.getValue()
+ map[v]
.getOrDefault(
pair.getKey(), 0));
}
}
}
// Store all queries related
// to vertex v
for (int freq : qv[v]) {
ans.put(new Point(v, freq),
map[v].containsValue(freq));
}
}
// Function to find answer for
// each queries
static void solveQuery(Point queries[],
int N, int q)
{
// Add all queries to qv
// where i();
for (Point p : queries) {
qv[p.x].add(p.y);
}
// Get sizes of all subtrees
size = new int[N + 1];
// calculate size[]
dfsSize(1, 0);
// Map will be used to store
// answers for current vertex
// on dfs
map = new HashMap[N + 1];
// To store answer of queries
ans = new HashMap<>();
// DFS Call
dfs(1, 0);
for (Point p : queries) {
// Print answer for each query
System.out.println(ans.get(p));
}
}
// Driver Code
public static void main(String[] args)
{
int N = 8;
adj = new ArrayList[N + 1];
for (int i = 1; i <= N; i++)
adj[i] = new ArrayList<>();
// Given edges (root=1)
add(1, 2);
add(1, 3);
add(2, 4);
add(2, 5);
add(5, 8);
add(5, 6);
add(6, 7);
// Store number given to vertices
// set num[0]=-1 because
// there is no vertex 0
num
= new int[] { -1, 11, 2, 7, 1,
-3, -1, -1, -3 };
// Queries
int q = 3;
// To store queries
Point queries[] = new Point[q];
// Given Queries
queries[0] = new Point(2, 3);
queries[1] = new Point(5, 2);
queries[2] = new Point(7, 1);
// Function Call
solveQuery(queries, N, q);
}
}
false
true
true
时间复杂度: O(N * Q)因为在每个查询中,都需要遍历树。
辅助空间: O(N + E + Q)
高效的方法:想法是将扩展不相交集联合用于上述方法:
- 创建一个数组size[]来存储子树的大小。
- 创建一个哈希映射数组map[] ,即 map[V][X] = 子树V中编号X 的总顶点数。
- 通过调用 dfsSize() 使用 DFS 遍历计算每个子树的大小。
- 通过调用dfs(V, p)使用DFS遍历,计算map[V]的值。
- 在遍历,来计算地图[V],选择具有除了父顶点,对最大尺寸(辟谷)V的相邻顶点。
- 对于连接操作,将 map[bigU] 的引用传递给 map[V],即map[V] = map[bigU] 。
- 并且 atlast 合并所有相邻顶点的映射, u到map[V] ,除了父顶点p和bigU顶点。
- 现在,检查map[V] 是否包含频率 F。如果是,则打印True否则打印False 。
下面是高效方法的实现:
Java
// Java program for the above approach
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@SuppressWarnings("unchecked")
public class Main {
// To store edges
static ArrayList adj[];
// num[v] = number assigned
// to vertex v
static int num[];
// map[v].get(c) = total vertices
// in subtree v having number c
static Map map[];
// size[v]=size of subtree v
static int size[];
static HashMap ans;
static ArrayList qv[];
// Function to add edges
static void add(int u, int v)
{
adj[u].add(v);
adj[v].add(u);
}
// Function to find subtree size
// of every vertex using dfsSize()
static void dfsSize(int v, int p)
{
size[v]++;
// Traverse dfsSize recursively
for (int u : adj[v]) {
if (p != u) {
dfsSize(u, v);
size[v] += size[u];
}
}
}
// Function to implement DFS Traversal
static void dfs(int v, int p)
{
int mx = -1, bigU = -1;
// Find adjacent vertex with
// maximum size
for (int u : adj[v]) {
if (u != p) {
dfs(u, v);
if (size[u] > mx) {
mx = size[u];
bigU = u;
}
}
}
if (bigU != -1) {
// Passing referencing
map[v] = map[bigU];
}
else {
// If no adjacent vertex
// present initialize map[v]
map[v] = new HashMap();
}
// Update frequency of current number
map[v].put(num[v],
map[v].getOrDefault(num[v], 0) + 1);
// Add all adjacent vertices
// maps to map[v]
for (int u : adj[v]) {
if (u != bigU && u != p) {
for (Entry
pair : map[u].entrySet()) {
map[v].put(
pair.getKey(),
pair.getValue()
+ map[v]
.getOrDefault(
pair.getKey(), 0));
}
}
}
// Store all queries related
// to vertex v
for (int freq : qv[v]) {
ans.put(new Point(v, freq),
map[v].containsValue(freq));
}
}
// Function to find answer for
// each queries
static void solveQuery(Point queries[],
int N, int q)
{
// Add all queries to qv
// where i();
for (Point p : queries) {
qv[p.x].add(p.y);
}
// Get sizes of all subtrees
size = new int[N + 1];
// calculate size[]
dfsSize(1, 0);
// Map will be used to store
// answers for current vertex
// on dfs
map = new HashMap[N + 1];
// To store answer of queries
ans = new HashMap<>();
// DFS Call
dfs(1, 0);
for (Point p : queries) {
// Print answer for each query
System.out.println(ans.get(p));
}
}
// Driver Code
public static void main(String[] args)
{
int N = 8;
adj = new ArrayList[N + 1];
for (int i = 1; i <= N; i++)
adj[i] = new ArrayList<>();
// Given edges (root=1)
add(1, 2);
add(1, 3);
add(2, 4);
add(2, 5);
add(5, 8);
add(5, 6);
add(6, 7);
// Store number given to vertices
// set num[0]=-1 because
// there is no vertex 0
num
= new int[] { -1, 11, 2, 7, 1,
-3, -1, -1, -3 };
// Queries
int q = 3;
// To store queries
Point queries[] = new Point[q];
// Given Queries
queries[0] = new Point(2, 3);
queries[1] = new Point(5, 2);
queries[2] = new Point(7, 1);
// Function Call
solveQuery(queries, N, q);
}
}
false
true
true
时间复杂度: O(N*logN 2 )
辅助空间: O(N + E + Q)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。