📜  树上的扩展不相交集并集

📅  最后修改于: 2021-04-22 08:04:53             🧑  作者: Mango

先决条件: DFS,树,DSU

给定一棵树,其中包含从值1到NE个边缘的N个节点和数组arr [] ,该数组表示与每个节点关联的数字。您还会得到Q查询,其中包含2个整数{V,F} 。对于每个查询,都有一个具有顶点V的子树,任务是检查是否存在与该子树中的每个节点关联的数字计数是否为F。如果是,则打印True,否则打印False

例子:

天真的方法:想法是使用DFS遍历遍历树,并计算与子树V的每个顶点关联的数的频率,并将结果存储在哈希图中。遍历后,我们只需要遍历哈希图以检查给定的频率数是否存在。

下面是上述方法的实现:

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)

高效的方法:想法是对以上方法使用扩展的不交集集合并集:

  1. 创建一个数组size []来存储子树的大小。
  2. 创建一个哈希数组map [],即map [V] [X] =子树V中数字X的总顶点。
  3. 通过调用dfsSize()使用DFS遍历计算每个子树的大小。
  4. 通过调用dfs(V,p)使用DFS遍历,计算map [V]的值。
  5. 在遍历中,要计算map [V] ,请选择除父顶点p之外具有最大大小( bigU )的V的相邻顶点。
  6. 对于联接操作,将map [bigU]的引用传递给map [V],即map [V] = map [bigU]
  7. 然后至少合并所有相邻顶点的映射umap [V] ,除了父顶点, pbigU顶点。
  8. 现在,检查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)