Open In App

Island Connectivity for Q queries

Last Updated : 26 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an integer N denoting the number of disconnected islands from 1 to N. You have to process Q queries of the following types:

  • Type 1 query: 0 u v => Connect islands u and v
  • Type 2 query: 1 u v => Print “YES” if islands u and v are connected otherwise print “NO”

Note: The connection between the islands follows transitive property.

Examples:

Input: N = 5, Q = 8, Queries = [[0 1 2], [1 2 1], [0 3 4], [1 1 4], [0 3 2], [1 2 3], [1 1 4], [1 1 5]]
Output: [YES, NO, YES, YES, NO]
Explanation: Initially islands = {1}, {2}, {3}, {4}, {5}

  • query[0] island ‘1’ and island ‘2’ merge => {1, 2}, {3}, {4}, {5}
  • query[1] => print YES as island 2 and island 1 is connected
  • query[2] island ‘3’ and island ‘4’ merge => {1, 2}, {3, 4}, {5}
  • query[3] => print NO as island 1 and island 4 are not connected.
  • query[4] island ‘3’ and island ‘2’ merge => {1, 2, 3, 4}, {5}
  • query[5] => print YES as island 2 and island 3 are connected.
  • query[6] => print YES as island 1 and island 4 are connected.
  • query[7] => print NO as island 1 and island 5 are not connected.

Input: N = 3, Q = 3, Queries = [[1 1 2], [1 2 3], [1 1 3]]
Output: [NO, NO, NO]
Explanation: Clearly there is no query of Type 1, hence all the islands remain disconnected.

Approach: We can solve this problem using the Disjoint Set Union (DSU) data structure:

Observations:

If we break down this question to a smaller scale, we observe that for each Type 1 query we have to put two disjoint island into a same set and for each query of Type 2 we have to know whether the two island belong to same set or are disjoint to each other. What data structure can be used to tackle this situation?

YES you guessed it right, this problem revolves around the construction of a Union and find functions of DSU.

  • For Type 1 query: Use Union() operation of DSU to Merge the two disjoint islands u and v.
  • For Type 2 query: Use Find() function to know whether the two island u and v have same parent or not.

Follow the steps to solve the problem:

  • Construct the Union() and Find() functions of DSU.
  • Initialize the Parent[] array for each island ‘i’ such that parent[i]=i.
  • Now process each query one by one as per below condition
    • If Type 1 query: Union(island u, island v)
    • If Type 2 query: Print Yes if Find(island u) == Find(island v), otherwise print NO.

Below is the code for the above approach:

C++




// C++ code for the above approach:
#include <bits/stdc++.h>
using namespace std;
 
// parent array to store parent of each island
int parent[100001];
 
// size array to apply DSU by size
int size[100001];
 
// This funtion initializes the DSU
void make(int i)
{
    parent[i] = i;
    size[i] = 1;
}
 
// This funtion finds the parent of
// Disjoint set having v
int find(int v)
{
    if (v == parent[v])
        return v;
 
    // path compression
    return parent[v] = find(parent[v]);
}
 
// This function Merges a and b
// into a single set
void Union(int a, int b)
{
    a = find(a);
    b = find(b);
    if (a != b) {
        if (size[a] < size[b])
            swap(a, b);
        parent[b] = a;
        size[a] += size[b];
    }
}
 
// Driver funtion
int main()
{
 
    // input test case
    int N = 5;
    int Q = 8;
    vector<vector<int> > Queries
        = { { 0, 1, 2 }, { 1, 2, 1 }, { 0, 3, 4 },
            { 1, 1, 4 }, { 0, 3, 2 }, { 1, 2, 3 },
            { 1, 1, 4 }, { 1, 1, 5 } };
 
    // Initialize the parent array
    for (int i = 1; i <= N; i++)
        make(i);
 
    // Process the queries
    for (auto e : Queries) {
        int type, u, v;
        type = e[0];
        u = e[1];
        v = e[2];
 
        // if type 2 query
        if (type) {
 
            // if parent of both u and v are same
            if (find(u) == find(v)) {
                cout << "Yes";
            }
 
            // if parent of u and v are different
            else
                cout << "No";
            cout << endl;
        }
 
        // if type 1 query
        else
            Union(u, v);
    }
}


Java




// Java code for the above approach:
 
import java.util.*;
 
class GFG {
 
    // parent array to store parent of each island
    static int[] parent = new int[100001];
 
    // size array to apply DSU by size
    static int[] size = new int[100001];
 
    // This funtion initializes the DSU
    static void make(int i)
    {
        parent[i] = i;
        size[i] = 1;
    }
 
    // This funtion finds the parent of
    // Disjoint set having v
    static int find(int v)
    {
        if (v == parent[v])
            return v;
 
        // path compression
        return parent[v] = find(parent[v]);
    }
 
    // This function Merges a and b
    // into a single set
    static void Union(int a, int b)
    {
        a = find(a);
        b = find(b);
 
        if (a != b) {
            if (size[a] < size[b]) {
                int temp = a;
                a = b;
                b = temp;
            }
            parent[b] = a;
            size[a] += size[b];
        }
    }
 
    // Driver funtion
    public static void main(String[] args)
    {
 
        // input test case
        int N = 5;
        int Q = 8;
        int[][] Queries
            = { { 0, 1, 2 }, { 1, 2, 1 }, { 0, 3, 4 },
                { 1, 1, 4 }, { 0, 3, 2 }, { 1, 2, 3 },
                { 1, 1, 4 }, { 1, 1, 5 } };
 
        // Initialize the parent array
        for (int i = 1; i <= N; i++) {
            make(i);
        }
 
        // Process the queries
        for (int[] e : Queries) {
            int type, u, v;
            type = e[0];
            u = e[1];
            v = e[2];
 
            // if type 2 query
            if (type == 1) {
 
                // if parent of both u and v are same
                if (find(u) == find(v)) {
                    System.out.print("Yes");
                }
 
                // if parent of u and v are different
                else {
                    System.out.print("No");
                }
 
                System.out.println();
            }
 
            // if type 1 query
            else
                Union(u, v);
        }
    }
}
 
// This code is contributed by ragul21


Python3




# Function to initialize the DSU
def make(i):
    parent[i] = i
    size[i] = 1
 
# Function to find the parent of a Disjoint set having v
def find(v):
    if v == parent[v]:
        return v
 
    # Path compression
    parent[v] = find(parent[v])
    return parent[v]
 
# Function to merge two sets into a single set
def Union(a, b):
    a = find(a)
    b = find(b)
    if a != b:
        if size[a] < size[b]:
            a, b = b, a
        parent[b] = a
        size[a] += size[b]
 
# Input test case
N = 5
Q = 8
Queries = [
    [0, 1, 2], [1, 2, 1], [0, 3, 4],
    [1, 1, 4], [0, 3, 2], [1, 2, 3],
    [1, 1, 4], [1, 1, 5]
]
 
# Initialize the parent array and size array
parent = [0] * (N + 1)
size = [0] * (N + 1)
 
for i in range(1, N + 1):
    make(i)
 
# Process the queries
for e in Queries:
    type, u, v = e
 
    # If it's a type 2 query
    if type:
        # If the parent of both u and v are the same
        if find(u) == find(v):
            print("Yes")
        else:
            print("No")
    else# If it's a type 1 query
        Union(u, v)


C#




using System;
using System.Collections.Generic;
 
class Program
{
    // parent array to store parent of each island
    static int[] parent = new int[100001];
 
    // size array to apply DSU by size
    static int[] size = new int[100001];
 
    // This function initializes the DSU
    static void Make(int i)
    {
        parent[i] = i;
        size[i] = 1;
    }
 
    // This function finds the parent of
    // Disjoint set having v
    static int Find(int v)
    {
        if (v == parent[v])
            return v;
 
        // path compression
        return parent[v] = Find(parent[v]);
    }
 
    // This function Merges a and b
    // into a single set
    static void Union(int a, int b)
    {
        a = Find(a);
        b = Find(b);
        if (a != b)
        {
            if (size[a] < size[b])
                Swap(ref a, ref b);
            parent[b] = a;
            size[a] += size[b];
        }
    }
 
    static void Swap(ref int a, ref int b)
    {
        int temp = a;
        a = b;
        b = temp;
    }
 
    // Driver function
    static void Main(string[] args)
    {
        // input test case
        int N = 5;
  
        List<int[]> Queries = new List<int[]>
        {
            new int[] { 0, 1, 2 }, new int[] { 1, 2, 1 }, new int[] { 0, 3, 4 },
            new int[] { 1, 1, 4 }, new int[] { 0, 3, 2 }, new int[] { 1, 2, 3 },
            new int[] { 1, 1, 4 }, new int[] { 1, 1, 5 }
        };
 
        // Initialize the parent array
        for (int i = 1; i <= N; i++)
            Make(i);
 
        // Process the queries
        foreach (var e in Queries)
        {
            int type = e[0];
            int u = e[1];
            int v = e[2];
 
            // if type 2 query
            if (type == 1)
            {
                // if parent of both u and v are same
                if (Find(u) == Find(v))
                {
                    Console.WriteLine("Yes");
                }
                // if parent of u and v are different
                else
                {
                    Console.WriteLine("No");
                }
            }
 
            // if type 1 query
            else
            {
                Union(u, v);
            }
        }
    }
}


Javascript




// Javascript code for the above approach:
 
// parent array to store parent of each island
let parent = new Array(100001);
 
// size array to apply DSU by size
let size = new Array(100001);
 
// This funtion initializes the DSU
function make(i) {
    parent[i] = i;
    size[i] = 1;
}
 
// This funtion finds the parent of
// Disjoint set having v
function find(v) {
    if (v == parent[v])
        return v;
 
    // path compression
    return parent[v] = find(parent[v]);
}
 
// This function Merges a and b
// into a single set
function Union(a, b) {
    a = find(a);
    b = find(b);
    if (a != b) {
        if (size[a] < size[b])
            swap(a, b);
        parent[b] = a;
        size[a] += size[b];
    }
}
 
// Driver function
function main() {
 
    // input test case
    let N = 5;
    let Q = 8;
    let Queries = [
        [0, 1, 2],
        [1, 2, 1],
        [0, 3, 4],
        [1, 1, 4],
        [0, 3, 2],
        [1, 2, 3],
        [1, 1, 4],
        [1, 1, 5]
    ];
 
    // Initialize the parent array
    for (let i = 1; i <= N; i++) {
        make(i);
    }
 
    // Process the queries
    for (let e of Queries) {
        let type, u, v;
        type = e[0];
        u = e[1];
        v = e[2];
 
        // if type 2 query
        if (type) {
 
            // if parent of both u and v are same
            if (find(u) == find(v)) {
                console.log("Yes");
            }
 
            // if parent of u and v are different
            else {
                console.log("No");
            }
        }
 
        // if type 1 query
        else {
            Union(u, v);
        }
    }
}
 
// Driver function call
main()
 
// This code is contributed by ragul21


Output

Yes
No
Yes
Yes
No









Complexity Analysis:

  • Time Complexity: max(N, Q) where N is the number of Islands and Q is total number of queries
  • Auxiliary Space: O(N) for the parent array


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads