Open In App

Difference between Smallest and Largest Component of the graph after each Query.

Last Updated : 07 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an integer N, denoting the total number of nodes in a graph without any edges, you have to process Q queries of the form u, v denoting that you have to add an edge between node u and v, after each query you have to print the size difference between largest component and the smallest component of the graph.

Examples:

Input: N = 2, Q = 1, queries = [[1, 2]]
Output: 0
Explanation:

  • Initial components = {{1}{2}}
  • After query[0]:
    • we have components = {{1, 2}}, Since we have only one component of size 2, the difference is 2-2 = 0.

Input: N = 4, Q = 2, queries = [[1, 2],[2, 4]]
Output: [1, 2]
Explanation:

  • Initial components = {{1},{2},{3},{4}},
  • After query[0]:
    • we have components = {{1, 2},{3},{4}} , So difference is, 2-1 = 1.
  • After query[1]:
    • we have components = {{1, 2, 4},{3}} , So difference is, 3-1 = 2.

Approach: We can use Disjoint-Set-Union(DSU) and Priority Queue(using multiset) to solve this question as discussed below:

For each query of adding an edge between ‘u‘ and ‘v’ we can use DSU to put both the nodes in the same set and update the size of the set they are in. Now we can put this new size in our multiset and remove the older sizes from it.

Simply print the difference between the maximum and minimum element of the multiset to get the answer for each query.

Firstly we have to construct our DSU functions as per the below steps:

  • Create a parent array of the size N i.e. the total number of nodes. This array will denote the parent of each node(component).
  • make(int i): Initialize parent[i]=i, sizez[i]=1, and for each i insert 1 inside a multiset ‘st’. This indicates that each node currently has size 1 and forms a component of its own.
  • find(int v): finds the parent of the component the node ‘v‘ belongs to.
  • Union(int a, int b): Merge the nodes ‘a‘ and ‘b‘ together. Delete the old sizes of ‘a‘ and ‘b‘ from the ‘st’ and insert the new size formed by the combination of ‘a‘ and ‘b

Now use the below algorithm to solve the problem:

  • Initialize the DSU data structure for each node from 1 to N, using the make function.
  • For each query, Union the nodes u and v.
  • Print the difference between the back and front element of the ‘st‘.

below is the implementation of the above algorithm:

C++




// C++ code for the above approach:
#include <bits/stdc++.h>
using namespace std;
// parent array for DSU to keep track
// of connected nodes having same parent
int parent[1000];
 
// DSU by size to speed up the
// time complexity
int sizes[1000];
 
// A single multiset used as a min
// as well as max heap
multiset<int> st;
 
// This function is to initialize
// DSU data structure
void make(int i)
{
    parent[i] = i;
    sizes[i] = 1;
    st.insert(1);
}
 
// This function is to return the
// parent of a node
int find(int v)
{
    if (v == parent[v])
        return v;
    return parent[v] = find(parent[v]);
}
 
// Union funtion to merge the components
// of graph and to update the multiset(heap)
void Union(int a, int b)
{
    a = find(a);
    b = find(b);
    if (a != b) {
        if (sizes[a] < sizes[b])
            swap(a, b);
        parent[b] = a;
 
        // Remove old size
        st.erase(st.find(sizes[a]));
 
        // Remove old size
        st.erase(st.find(sizes[b]));
 
        // Insert new updated size
        st.insert(sizes[a] + sizes[b]);
        sizes[a] += sizes[b];
    }
}
 
// Driver Function
int main()
{
    int N = 4;
    int Q = 2;
 
    // Initialize DSU for each node
    // from 1 to N
    for (int i = 1; i <= N; i++) {
        make(i);
    }
    vector<vector<int> > queries = { { 1, 2 }, { 2, 4 } };
    for (int i = 0; i < Q; i++) {
        int u = queries[i][0];
        int v = queries[i][1];
 
        // Union u and v, as we add
        // edge between them
        Union(u, v);
 
        // Using multiset as min heap
        // from front
        int a = *st.begin();
 
        // Using multiset as max-heap
        // from back
        int b = *(--st.end());
        cout << b - a << endl;
    }
}


Java




import java.util.*;
 
public class GFG {
    // Parent array for DSU to keep track of connected nodes having the same parent
    static int[] parent = new int[1000];
     
    // Sizes array to store the size of each component
    static int[] sizes = new int[1000];
     
    // A single multiset used as a min as well as max heap
    static List<Integer> st = new ArrayList<>();
 
    // Function to initialize DSU data structure
    static void make(int i) {
        parent[i] = i;
        sizes[i] = 1;
        st.add(1);
    }
 
    // Function to return the parent of a node with path compression
    static int find(int v) {
        if (v == parent[v]) {
            return v;
        }
        parent[v] = find(parent[v]);
        return parent[v];
    }
 
    // Union function to merge the components of the graph and update the list (heap)
    static void union(int a, int b) {
        a = find(a);
        b = find(b);
        if (a != b) {
            if (sizes[a] < sizes[b]) {
                int temp = a;
                a = b;
                b = temp;
            }
            parent[b] = a;
 
            // Remove old size
            st.remove(Integer.valueOf(sizes[a]));
 
            // Remove old size
            st.remove(Integer.valueOf(sizes[b]));
 
            // Insert new updated size
            st.add(sizes[a] + sizes[b]);
            sizes[a] += sizes[b];
        }
    }
 
    // Driver Function
    public static void main(String[] args) {
        int N = 4;
        int Q = 2;
 
        // Initialize DSU for each node from 1 to N
        for (int i = 1; i <= N; i++) {
            make(i);
        }
 
        int[][] queries = {{1, 2}, {2, 4}};
        for (int i = 0; i < Q; i++) {
            int u = queries[i][0];
            int v = queries[i][1];
 
            // Union u and v, as we add an edge between them
            union(u, v);
 
            // Using list as min-heap
            int a = Collections.min(st);
 
            // Using list as max-heap
            int b = Collections.max(st);
            System.out.println(b - a);
        }
    }
}


Python3




# parent array for DSU to keep track
# of connected nodes having same parent
parent = [0] * 1000
# DSU by size to speed up the
# time complexity
sizes = [0] * 1000
 
# A single multiset used as a min
# as well as max heap
st = []
 
# This function is to initialize
# DSU data structure
def make(i):
    parent[i] = i
    sizes[i] = 1
    st.append(1)
 
# This function is to return the
# parent of a node
def find(v):
    if v == parent[v]:
        return v
    parent[v] = find(parent[v])
    return parent[v]
 
# Union function to merge the components
# of the graph and to update the list (heap)
def union(a, b):
    a = find(a)
    b = find(b)
    if a != b:
        if sizes[a] < sizes[b]:
            a, b = b, a
        parent[b] = a
 
        # Remove old size
        st.remove(sizes[a])
 
        # Remove old size
        st.remove(sizes[b])
 
        # Insert new updated size
        st.append(sizes[a] + sizes[b])
        sizes[a] += sizes[b]
 
# Driver Function
if __name__ == "__main__":
    N = 4
    Q = 2
 
    # Initialize DSU for each node
    # from 1 to N
    for i in range(1, N + 1):
        make(i)
 
    queries = [[1, 2], [2, 4]]
    for i in range(Q):
        u = queries[i][0]
        v = queries[i][1]
 
        # Union u and v, as we add
        # an edge between them
        union(u, v)
 
        # Using list as min-heap
        a = min(st)
 
        # Using list as max-heap
        b = max(st)
        print(b - a)


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
public class GFG
{
    // Parent array for DSU to keep track of connected nodes having the same parent
    static int[] parent = new int[1000];
     
    // Sizes array to store the size of each component
    static int[] sizes = new int[1000];
     
    // A single multiset used as a min as well as max heap
    static List<int> st = new List<int>();
 
    // Function to initialize DSU data structure
    static void Make(int i)
    {
        parent[i] = i;
        sizes[i] = 1;
        st.Add(1);
    }
 
    // Function to return the parent of a node with path compression
    static int Find(int v)
    {
        if (v == parent[v])
        {
            return v;
        }
        parent[v] = Find(parent[v]);
        return parent[v];
    }
 
    // Union function to merge the components of the graph and update the list (heap)
    static void Union(int a, int b)
    {
        a = Find(a);
        b = Find(b);
        if (a != b)
        {
            if (sizes[a] < sizes[b])
            {
                int temp = a;
                a = b;
                b = temp;
            }
            parent[b] = a;
 
            // Remove old size
            st.Remove(sizes[a]);
 
            // Remove old size
            st.Remove(sizes[b]);
 
            // Insert new updated size
            st.Add(sizes[a] + sizes[b]);
            sizes[a] += sizes[b];
        }
    }
 
    // Driver Function
    public static void Main(string[] args)
    {
        int N = 4;
        int Q = 2;
 
        // Initialize DSU for each node from 1 to N
        for (int i = 1; i <= N; i++)
        {
            Make(i);
        }
 
        int[][] queries = new int[][] { new int[] { 1, 2 }, new int[] { 2, 4 } };
        for (int i = 0; i < Q; i++)
        {
            int u = queries[i][0];
            int v = queries[i][1];
 
            // Union u and v, as we add an edge between them
            Union(u, v);
 
            // Using list as min-heap
            int a = st.Min();
 
            // Using list as max-heap
            int b = st.Max();
            Console.WriteLine(b - a);
        }
    }
}


Javascript




// Parent array for DSU to keep track of connected nodes having the same parent
const parent = new Array(1000);
for (let i = 0; i < parent.length; i++) {
    parent[i] = i;
}
 
// Sizes array to store the size of each component
const sizes = new Array(1000).fill(1);
 
// A single multiset used as a min as well as max heap
const st = [];
 
// Function to initialize DSU data structure
function make(i) {
    parent[i] = i;
    sizes[i] = 1;
    st.push(1);
}
 
// Function to return the parent of a node with path compression
function find(v) {
    if (v === parent[v]) {
        return v;
    }
    parent[v] = find(parent[v]);
    return parent[v];
}
 
// Union function to merge the components of the graph and update the list (heap)
function union(a, b) {
    a = find(a);
    b = find(b);
    if (a !== b) {
        if (sizes[a] < sizes[b]) {
            [a, b] = [b, a]; // Swap a and b
        }
        parent[b] = a;
 
        // Remove old size
        st.splice(st.indexOf(sizes[a]), 1);
 
        // Remove old size
        st.splice(st.indexOf(sizes[b]), 1);
 
        // Insert new updated size
        st.push(sizes[a] + sizes[b]);
        sizes[a] += sizes[b];
    }
}
 
// Driver Function
function main() {
    const N = 4;
    const Q = 2;
 
    // Initialize DSU for each node from 1 to N
    for (let i = 1; i <= N; i++) {
        make(i);
    }
 
    const queries = [[1, 2], [2, 4]];
    for (let i = 0; i < Q; i++) {
        const u = queries[i][0];
        const v = queries[i][1];
 
        // Union u and v, as we add an edge between them
        union(u, v);
 
        // Using array as min-heap
        const a = Math.min(...st);
 
        // Using array as max-heap
        const b = Math.max(...st);
        console.log(b - a);
    }
}
 
main();


Output

1
2







Time Complexity: O(Q(logN) + N), where Q is the number of queries and N is the number of nodes.
Auxiliary Space: O(N), where N is the number of nodes.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads