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++ 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 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 |
# 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)
|
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 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 |
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