Given an array arr[] of N integers. and an integer K. Construct a weighted undirected graph of N vertices numbered from 0 to N-1. An edge between the vertices i and j (j>i) is added if any one of the following conditions is satisfied:
- If j = i + 1, add an edge of weight K between vertices i and j.
- If min(ai , ai+1 ,....., aj) = gcd(ai , ai+1 ,....., aj), add an edge of weight min(ai , ai+1 ,....., aj) between vertices i and j.
The task is to determine the MST(Minimum Spanning Tree) of the resultant graph.
Examples:
Input: N=4, K=5, arr = [3, 2, 6, 3]
Output: 10
Explanation: The image shows that the cost of MST is 5 + 2 + 3 = 10
Input: N=4, K=3, arr = [5, 10, 2, 3]
Output: 8
Explanation: The image shows that the cost of MST is 3 + 2 + 3 = 8
Approach: The problem can be solved using the following approach:
The idea is to consider the edges which have a smaller weight first. This can be done by storing array along with its index and then sort it according to the value. For any element with index idx, we will have to move left and right separately. If we add a new element with index j while moving left or right, the condition gcd(curr_gcd, a[j]) = a[idx] should be satisfied. If it is satisfied, we can add an edge of weight a[idx] between vertices idx and j. If idx and j are already in same Connected Component then no edge will be added and we will simply break and repeat the process for remaining elements.
Follow the steps to solve the above problem:
- Create a vector of pairs
vpwhere each pair consists of the array element and its index and sort this vectorvpin ascending order based on the array values. - Initialize total weight of the Minimum Spanning Tree (MST) as
ans= 0. - Iterate through sorted elements:
- Get the index of the current element as
idx,set j to idx+1 and curr_gcd to a[idx]. - While j is less than the size of the array:
- Update the curr_gcd to gcd(curr_gcd, a[j]).
- If curr_gcd is equal to a[idx] then, check whether vertices idx and j are in same connected component (this can be done using Disjoint Set Union). If they are not in same component add the edge weight (
a[idx]) to the totalans and increment j, or else break.
- Repeat the similar logic for j=idx-1.
- Get the index of the current element as
- Iterate through i=0 to n-1,
- If vertices i and i+1 are not in same component add the edge weight k to the total
ans.
- If vertices i and i+1 are not in same component add the edge weight k to the total
- Return ans.
Below is the implementation of above approach:
#include <bits/stdc++.h>
using namespace std;
// Rank array for disjoint-set union
vector<int> rnk(200001);
// Parent array for disjoint-set union
vector<int> parent(200001);
// Function to create a new set with element 'v'
void make_set(int v)
{
// Each element is initially its own parent
parent[v] = v;
// Initialize the rank to 0 (used in union)
rnk[v] = 0;
}
// Function to find the representative (parent) of a set
// containing 'v'
int find_par(int v)
{
if (v == parent[v])
return v;
// Path compression for optimization
return parent[v] = find_par(parent[v]);
}
// Function to union two sets with elements 'a' and 'b'
void union_sets(int a, int b)
{
a = find_par(a);
b = find_par(b);
if (a != b) {
if (rnk[a] < rnk[b])
swap(a, b);
parent[b] = a;
if (rnk[a] == rnk[b])
rnk[a]++;
}
}
// Function to solve the problem and find the Minimum
// Spanning Tree (MST)
int solve(vector<int>& a, int n, int k)
{
vector<pair<int, int> > vp(n);
for (int i = 0; i < n; i++) {
// Store the original index of each element
vp[i].second = i;
// Store the value of each element
vp[i].first = a[i];
}
// Sort elements by their values
sort(vp.begin(), vp.end());
// Initialize disjoint-set data structures for each
// element
for (int i = 0; i < n; i++) {
make_set(i);
}
int i = 0;
// Initialize the total weight of the MST
int ans = 0;
while (i < n) {
// Get the original index of the element
int idx = vp[i].second;
// If the element value is greater than 'k', break
if (vp[i].first > k)
break;
int j = idx + 1;
// Initialize the current GCD value
int curr_gcd = a[idx];
// Explore elements to the right
while (j < n && curr_gcd == a[idx]) {
// Calculate the GCD
curr_gcd = __gcd(curr_gcd, a[j]);
// If the GCD condition is not met, break
if (curr_gcd != a[idx])
break;
int x = find_par(idx);
int y = find_par(j);
// If they are already in the same
// component, break
if (x == y)
break;
// Union two sets and update 'ans'
union_sets(x, y);
ans += a[idx];
j++;
}
// Explore elements to the left
j = idx - 1;
curr_gcd = a[idx];
while (j >= 0 && curr_gcd == a[idx]) {
curr_gcd = __gcd(curr_gcd, a[j]);
// If the GCD condition is not met, break
if (curr_gcd != a[idx])
break;
int x = find_par(idx);
int y = find_par(j);
// If they are already in the same
// component, break
if (x == y)
break;
union_sets(x, y);
ans = ans + a[idx];
j--;
}
i++;
}
// Add edges with weight 'k' between adjacent elements
for (int i = 0; i < n - 1; i++) {
int x = find_par(i);
int y = find_par(i + 1);
if (x != y) {
union_sets(x, y);
// Update 'ans' with the edge weight 'k'
ans = ans + k;
}
}
// Return the total weight of the MST
return ans;
}
// Driver Code
int main()
{
int N = 4, K = 5;
vector<int> a = { 3, 2, 6, 3 };
int result = solve(a, N, K);
// Print the total weight of the MST
cout << result << "\n";
}
import java.util.Arrays;
import java.util.Collections;
import java.util.Vector;
public class MinimumSpanningTree {
// Rank array for disjoint-set union
static Vector<Integer> rnk = new Vector<>(Collections.nCopies(200001, 0));
// Parent array for disjoint-set union
static Vector<Integer> parent = new Vector<>(Collections.nCopies(200001, 0));
// Function to create a new set with element 'v'
static void makeSet(int v) {
// Each element is initially its own parent
parent.set(v, v);
// Initialize the rank to 0 (used in union)
rnk.set(v, 0);
}
// Function to find the representative (parent) of a set
// containing 'v'
static int findPar(int v) {
if (v == parent.get(v))
return v;
// Path compression for optimization
parent.set(v, findPar(parent.get(v)));
return parent.get(v);
}
// Function to union two sets with elements 'a' and 'b'
static void unionSets(int a, int b) {
a = findPar(a);
b = findPar(b);
if (a != b) {
if (rnk.get(a) < rnk.get(b))
Collections.swap(rnk, a, b);
parent.set(b, a);
if (rnk.get(a) == rnk.get(b))
rnk.set(a, rnk.get(a) + 1);
}
}
// Function to solve the problem and find the Minimum
// Spanning Tree (MST)
static int solve(Vector<Integer> a, int n, int k) {
Vector<Pair<Integer, Integer>> vp = new Vector<>(n);
for (int i = 0; i < n; i++) {
// Store the original index of each element
vp.add(new Pair<>(a.get(i), i));
// Store the value of each element
vp.set(i, new Pair<>(a.get(i), i));
}
// Sort elements by their values
Collections.sort(vp, (x, y) -> x.first - y.first);
// Initialize disjoint-set data structures for each
// element
for (int i = 0; i < n; i++) {
makeSet(i);
}
int j = 0;
// Initialize the total weight of the MST
int ans = 0;
while (j < n) {
// Get the original index of the element
int idx = vp.get(j).second;
// If the element value is greater than 'k', break
if (vp.get(j).first > k)
break;
int i = idx + 1;
// Initialize the current GCD value
int currGcd = a.get(idx);
// Explore elements to the right
while (i < n && currGcd == a.get(idx)) {
// Calculate the GCD
currGcd = gcd(currGcd, a.get(i));
// If the GCD condition is not met, break
if (currGcd != a.get(idx))
break;
int x = findPar(idx);
int y = findPar(i);
// If they are already in the same component, break
if (x == y)
break;
// Union two sets and update 'ans'
unionSets(x, y);
ans += a.get(idx);
i++;
}
// Explore elements to the left
i = idx - 1;
currGcd = a.get(idx);
while (i >= 0 && currGcd == a.get(idx)) {
currGcd = gcd(currGcd, a.get(i));
// If the GCD condition is not met, break
if (currGcd != a.get(idx))
break;
int x = findPar(idx);
int y = findPar(i);
// If they are already in the same component, break
if (x == y)
break;
unionSets(x, y);
ans += a.get(idx);
i--;
}
j++;
}
// Add edges with weight 'k' between adjacent elements
for (int i = 0; i < n - 1; i++) {
int x = findPar(i);
int y = findPar(i + 1);
if (x != y) {
unionSets(x, y);
// Update 'ans' with the edge weight 'k'
ans += k;
}
}
// Return the total weight of the MST
return ans;
}
// Utility function to calculate GCD
static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// Driver Code
public static void main(String[] args) {
int N = 4, K = 5;
Vector<Integer> a = new Vector<>(Arrays.asList(3, 2, 6, 3));
int result = solve(a, N, K);
// Print the total weight of the MST
System.out.println(result);
}
static class Pair<X, Y> {
X first;
Y second;
public Pair(X first, Y second) {
this.first = first;
this.second = second;
}
}
}
// This code is contributed by shivamgupta310570
# Rank array for disjoint-set union
rnk = [0] * 200001
# Parent array for disjoint-set union
parent = [0] * 200001
# Function to create a new set with element 'v'
def make_set(v):
# Each element is initially its own parent
parent[v] = v
# Initialize the rank to 0 (used in union)
rnk[v] = 0
# Function to find the representative (parent) of a set
# containing 'v'
def find_par(v):
if v == parent[v]:
return v
# Path compression for optimization
parent[v] = find_par(parent[v])
return parent[v]
# Function to union two sets with elements 'a' and 'b'
def union_sets(a, b):
a = find_par(a)
b = find_par(b)
if a != b:
if rnk[a] < rnk[b]:
a, b = b, a
parent[b] = a
if rnk[a] == rnk[b]:
rnk[a] += 1
# Function to solve the problem and find the Minimum
# Spanning Tree (MST)
def solve(a, n, k):
vp = [(a[i], i) for i in range(n)]
# Sort elements by their values
vp.sort()
# Initialize disjoint-set data structures for each
# element
for i in range(n):
make_set(i)
i = 0
# Initialize the total weight of the MST
ans = 0
while i < n:
# Get the original index of the element
idx = vp[i][1]
# If the element value is greater than 'k', break
if vp[i][0] > k:
break
j = idx + 1
# Initialize the current GCD value
curr_gcd = a[idx]
# Explore elements to the right
while j < n and curr_gcd == a[idx]:
# Calculate the GCD
curr_gcd = math.gcd(curr_gcd, a[j])
# If the GCD condition is not met, break
if curr_gcd != a[idx]:
break
x = find_par(idx)
y = find_par(j)
# If they are already in the same
# component, break
if x == y:
break
# Union two sets and update 'ans'
union_sets(x, y)
ans += a[idx]
j += 1
# Explore elements to the left
j = idx - 1
curr_gcd = a[idx]
while j >= 0 and curr_gcd == a[idx]:
curr_gcd = math.gcd(curr_gcd, a[j])
# If the GCD condition is not met, break
if curr_gcd != a[idx]:
break
x = find_par(idx)
y = find_par(j)
# If they are already in the same
# component, break
if x == y:
break
union_sets(x, y)
ans = ans + a[idx]
j -= 1
i += 1
# Add edges with weight 'k' between adjacent elements
for i in range(n - 1):
x = find_par(i)
y = find_par(i + 1)
if x != y:
union_sets(x, y)
# Update 'ans' with the edge weight 'k'
ans = ans + k
# Return the total weight of the MST
return ans
# Driver Code
import math
N = 4
K = 5
a = [3, 2, 6, 3]
result = solve(a, N, K)
# Print the total weight of the MST
print(result)
using System;
using System.Collections.Generic;
class Program {
// Rank array for disjoint-set union
static int[] rnk = new int[200001];
// Parent array for disjoint-set union
static int[] parent = new int[200001];
// Function to create a new set with element 'v'
static void MakeSet(int v)
{
// Each element is initially its own parent
parent[v] = v;
// Initialize the rank to 0 (used in union)
rnk[v] = 0;
}
// Function to find the representative (parent) of a set
// containing 'v'
static int FindParent(int v)
{
if (v == parent[v])
return v;
// Path compression for optimization
return parent[v] = FindParent(parent[v]);
}
// Function to union two sets with elements 'a' and 'b'
static void UnionSets(int a, int b)
{
a = FindParent(a);
b = FindParent(b);
if (a != b) {
if (rnk[a] < rnk[b])
Swap(ref a, ref b);
parent[b] = a;
if (rnk[a] == rnk[b])
rnk[a]++;
}
}
// Function to solve the problem and find the Minimum
// Spanning Tree (MST)
static int Solve(List<int> a, int n, int k)
{
List<Tuple<int, int> > vp
= new List<Tuple<int, int> >(n);
for (int i = 0; i < n; i++) {
// Store the original index of each element
vp.Add(new Tuple<int, int>(a[i], i));
}
// Sort elements by their values
vp.Sort();
// Initialize disjoint-set data structures for each
// element
for (int i = 0; i < n; i++) {
MakeSet(i);
}
int j = 0;
// Initialize the total weight of the MST
int ans = 0;
while (j < n) {
// Get the original index of the element
int idx = vp[j].Item2;
// If the element value is greater than 'k',
// break
if (vp[j].Item1 > k)
break;
int i = idx + 1;
// Initialize the current GCD value
int currGcd = a[idx];
// Explore elements to the right
while (i < n && currGcd == a[idx]) {
// Calculate the GCD
currGcd = Gcd(currGcd, a[i]);
// If the GCD condition is not met, break
if (currGcd != a[idx])
break;
int x = FindParent(idx);
int y = FindParent(i);
// If they are already in the same
// component, break
if (x == y)
break;
// Union two sets and update 'ans'
UnionSets(x, y);
ans += a[idx];
i++;
}
// Explore elements to the left
i = idx - 1;
currGcd = a[idx];
while (i >= 0 && currGcd == a[idx]) {
currGcd = Gcd(currGcd, a[i]);
// If the GCD condition is not met, break
if (currGcd != a[idx])
break;
int x = FindParent(idx);
int y = FindParent(i);
// If they are already in the same
// component, break
if (x == y)
break;
UnionSets(x, y);
ans = ans + a[idx];
i--;
}
j++;
}
// Add edges with weight 'k' between adjacent
// elements
for (int i = 0; i < n - 1; i++) {
int x = FindParent(i);
int y = FindParent(i + 1);
if (x != y) {
UnionSets(x, y);
// Update 'ans' with the edge weight 'k'
ans = ans + k;
}
}
// Return the total weight of the MST
return ans;
}
// Function to calculate GCD
static int Gcd(int a, int b)
{
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
// Function to swap two values
static void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
// Driver Code
static void Main()
{
int N = 4, K = 5;
List<int> a = new List<int>{ 3, 2, 6, 3 };
int result = Solve(a, N, K);
// Print the total weight of the MST
Console.WriteLine(result);
}
}
// Function to create a new set with element 'v'
function makeSet(v, parent, rnk) {
parent[v] = v;
rnk[v] = 0;
}
// Function to find the representative (parent) of a set containing 'v'
function findPar(v, parent) {
if (v === parent[v]) {
return v;
}
// Path compression for optimization
parent[v] = findPar(parent[v], parent);
return parent[v];
}
// Function to union two sets with elements 'a' and 'b'
function unionSets(a, b, parent, rnk) {
a = findPar(a, parent);
b = findPar(b, parent);
if (a !== b) {
if (rnk[a] < rnk[b]) {
[rnk[a], rnk[b]] = [rnk[b], rnk[a]];
}
parent[b] = a;
if (rnk[a] === rnk[b]) {
rnk[a]++;
}
}
}
// Function to solve the problem and find the Minimum Spanning Tree (MST)
function solve(a, n, k) {
const vp = Array.from({ length: n }, (_, i) => ({ value: a[i], index: i }));
// Sort elements by their values
vp.sort((x, y) => x.value - y.value);
// Initialize disjoint-set data structures for each element
const parent = new Array(n);
const rnk = new Array(n);
for (let i = 0; i < n; i++) {
makeSet(i, parent, rnk);
}
let j = 0;
// Initialize the total weight of the MST
let ans = 0;
while (j < n) {
// Get the original index of the element
const idx = vp[j].index;
// If the element value is greater than 'k', break
if (vp[j].value > k) {
break;
}
let i = idx + 1;
// Initialize the current GCD value
let currGcd = a[idx];
// Explore elements to the right
while (i < n && currGcd === a[idx]) {
// Calculate the GCD
currGcd = gcd(currGcd, a[i]);
// If the GCD condition is not met, break
if (currGcd !== a[idx]) {
break;
}
const x = findPar(idx, parent);
const y = findPar(i, parent);
// If they are already in the same component, break
if (x === y) {
break;
}
// Union two sets and update 'ans'
unionSets(x, y, parent, rnk);
ans += a[idx];
i++;
}
// Explore elements to the left
i = idx - 1;
currGcd = a[idx];
while (i >= 0 && currGcd === a[idx]) {
currGcd = gcd(currGcd, a[i]);
// If the GCD condition is not met, break
if (currGcd !== a[idx]) {
break;
}
const x = findPar(idx, parent);
const y = findPar(i, parent);
// If they are already in the same component, break
if (x === y) {
break;
}
unionSets(x, y, parent, rnk);
ans += a[idx];
i--;
}
j++;
}
// Add edges with weight 'k' between adjacent elements
for (let i = 0; i < n - 1; i++) {
const x = findPar(i, parent);
const y = findPar(i + 1, parent);
if (x !== y) {
unionSets(x, y, parent, rnk);
// Update 'ans' with the edge weight 'k'
ans += k;
}
}
// Return the total weight of the MST
return ans;
}
// Utility function to calculate GCD
function gcd(a, b) {
return b === 0 ? a : gcd(b, a % b);
}
// Driver Code
const N = 4, K = 5;
const a = [3, 2, 6, 3];
const result = solve(a, N, K);
// Print the total weight of the MST
console.log(result);
Output
10
Time Complexity: O(N logN), where N is the size of the input array arr[].
Auxiliary Space: O(N)

