Given a connected undirected weighted graph with N nodes and M edges. The task is to perform given queries and find the weight of the minimum spanning tree. Queries are of three types:
- query(1) -> Find the weight of the minimum spanning tree.
- query(2, x, y) -> Change the weight of the edge between the nodes x and y to 0.
- query(3, x, y) -> Restore the weight of the edge between the nodes x and y to its original weight.
Examples:
Input:
query(2, 1, 2),
query(1),
query(3, 1, 2),
query(1)
Output:
2
3
Input:
query(1),
query(2, 3, 4),
query(1)
Output :
4
2
Approach: Let’s first compute MST of the initial graph before performing any queries and let T be this MST. The crucial observation is that at any point while handling the queries, the weight of the MST of the current graph can be computed by running Kruskal’s algorithm on edges with zero weight at this point and edges of T. So, keep edges with weight zero in a data structure and after query of type 2 and type 3 compute weight of minimum spanning tree.
Below is the implementation of the above approach:
// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
#define N 2005
// To store vertices, edges
// and the required answer
int n, m, ans;
// To store parent and rank
int par[N], Rank[N];
// To store edges and the edges in MST
vector<pair<int, pair<int, int> > > edges, mst;
// To store the edges with weight zero
queue<pair<int, int> > zeros;
// Function for initialize
void initialize()
{
for (int i = 0; i <= n; i++) {
par[i] = i;
Rank[i] = 0;
}
}
// Function to add edges
void Add_edge(int u, int v, int weight)
{
edges.push_back({ weight, { u, v } });
}
// Utility function to find set of an element i
// (uses path compression technique)
int find(int x)
{
if (par[x] != x)
par[x] = find(par[x]);
return par[x];
}
// Function that performs union of two sets x and y
// (uses union by rank)
void Union(int x, int y)
{
int xroot = find(x);
int yroot = find(y);
if (Rank[xroot] < Rank[yroot])
par[xroot] = yroot;
else if (Rank[xroot] > Rank[yroot])
par[yroot] = xroot;
else {
par[yroot] = xroot;
Rank[xroot]++;
}
}
// Function to compute minimum spanning tree
void compute_MST()
{
// Sort edges in increasing order of weight
sort(edges.begin(), edges.end());
// Go through all the edges
for (int i = 0; i < m; i++) {
int u = find(edges[i].second.first);
int v = find(edges[i].second.second);
if (u == v)
continue;
// Build minimum spanning tree
// and store minimum cost
mst.push_back(edges[i]);
ans += edges[i].first;
Union(u, v);
}
}
// Function to find the cost of minimum
// spanning tree
void Modified_Kruskal(pair<int, int> x)
{
initialize();
// Make answer zero
ans = 0;
int sz = zeros.size();
// Keep the edges which only have zero weights
// and remove all the other edges
for (int i = 0; i < sz; i++) {
pair<int, int> Front = zeros.front();
zeros.pop();
if (Front.first == x.first
and Front.second == x.second)
continue;
// Make union between the vertices of
// edges which have weight zero and keep
// them in queue
Union(Front.first, Front.second);
zeros.push(Front);
}
// Find the cost of the minimum spanning tree
for (int i = 0; i < mst.size(); i++) {
int u = find(mst[i].second.first);
int v = find(mst[i].second.second);
if (u == v)
continue;
ans += mst[i].first;
Union(u, v);
}
}
// Function to handle different queries
void query(int type, int u = 0, int v = 0)
{
// Update edge weight to 0
if (type == 2) {
// push edge in zeros
zeros.push({ u, v });
Modified_Kruskal({ -1, -1 });
}
// Restore edge weight to original value
else if (type == 3) {
// push edge in zeros
zeros.push({ u, v });
Modified_Kruskal({ u, v });
}
else
cout << ans << endl;
}
// Driver code
int main()
{
// Number of nodes and edges
n = 4, m = 4;
initialize();
// Add edges
Add_edge(1, 2, 1);
Add_edge(2, 3, 1);
Add_edge(3, 4, 1);
Add_edge(4, 1, 1);
// Build the minimum spanning tree
compute_MST();
// Execute queries
query(2, 1, 2);
query(1);
query(3, 1, 2);
query(1);
return 0;
}
import java.util.*;
class Main {
static final int N = 2005;
static int n, m, ans;
static int[] par, Rank;
static List<Pair> edges, mst;
static Queue<Pair> zeros;
// Pair class to represent edges and vertices
static class Pair {
int first, second;
Pair(int first, int second) {
this.first = first;
this.second = second;
}
}
// Function to initialize data structures
static void initialize() {
par = new int[N];
Rank = new int[N];
for (int i = 0; i <= n; i++) {
par[i] = i;
Rank[i] = 0;
}
}
// Function to add edges
static void Add_edge(int u, int v, int weight) {
edges.add(new Pair(weight, (u << 10) | v));
}
// Utility function to find set of an element i (uses path compression technique)
static int find(int x) {
if (par[x] != x)
par[x] = find(par[x]);
return par[x];
}
// Function that performs union of two sets x and y (uses union by rank)
static void Union(int x, int y) {
int xroot = find(x);
int yroot = find(y);
if (Rank[xroot] < Rank[yroot])
par[xroot] = yroot;
else if (Rank[xroot] > Rank[yroot])
par[yroot] = xroot;
else {
par[yroot] = xroot;
Rank[xroot]++;
}
}
// Function to compute minimum spanning tree
static void computeMST() {
// Sort edges in increasing order of weight
Collections.sort(edges, Comparator.comparingInt(a -> a.first));
// Go through all the edges
for (int i = 0; i < m; i++) {
int u = find(edges.get(i).second >> 10);
int v = find(edges.get(i).second & ((1 << 10) - 1));
if (u == v)
continue;
// Build minimum spanning tree and store minimum cost
mst.add(edges.get(i));
ans += edges.get(i).first;
Union(u, v);
}
}
// Function to find the cost of the minimum spanning tree
static void modifiedKruskal(Pair x) {
initialize();
ans = 0;
int sz = zeros.size();
// Keep the edges which only have zero weights and remove all the other edges
for (int i = 0; i < sz; i++) {
Pair front = zeros.poll();
if (front.first == x.first && front.second == x.second)
continue;
// Make union between the vertices of edges which have weight zero and keep them in the queue
Union(front.first, front.second);
zeros.add(front);
}
// Find the cost of the minimum spanning tree
for (int i = 0; i < mst.size(); i++) {
int u = find(mst.get(i).second >> 10);
int v = find(mst.get(i).second & ((1 << 10) - 1));
if (u == v)
continue;
ans += mst.get(i).first;
Union(u, v);
}
}
// Function to handle different queries
static void query(int type, int u, int v) {
// Update edge weight to 0
if (type == 2) {
zeros.add(new Pair(u, v));
modifiedKruskal(new Pair(-1, -1));
}
// Restore edge weight to original value
else if (type == 3) {
zeros.add(new Pair(u, v));
modifiedKruskal(new Pair(u, v));
} else
System.out.println(ans);
}
// Driver code
public static void main(String[] args) {
// Number of nodes and edges
n = 4;
m = 4;
initialize();
// Initialize data structures
edges = new ArrayList<>();
mst = new ArrayList<>();
zeros = new LinkedList<>();
// Add edges
Add_edge(1, 2, 1);
Add_edge(2, 3, 1);
Add_edge(3, 4, 1);
Add_edge(4, 1, 1);
// Build the minimum spanning tree
computeMST();
// Execute queries
query(2, 1, 2);
query(1, 0, 0);
query(3, 1, 2);
query(1, 0, 0);
}
}
# Python3 implementation of the approach
from collections import deque
N = 2005
# To store vertices, edges
# and the required answer
n, m, ans = 0, 0, 0
# To store parent and rank
par = [0] * N
Rank = [0] * N
# To store edges and the edges in MST
edges, mst = [], []
# To store the edges with weight zero
zeroes = deque()
# Function for initialize
def initialize():
for i in range(n + 1):
par[i] = i
Rank[i] = 0
# Function to add edges
def add_edge(u: int, v: int, weight: int):
edges.append((weight, (u, v)))
# Utility function to find set of an element i
# (uses path compression technique)
def find(x: int) -> int:
if par[x] != x:
par[x] = find(par[x])
return par[x]
# Function that performs union of two sets x and y
# (uses union by rank)
def union(x: int, y: int):
xroot = find(x)
yroot = find(y)
if Rank[xroot] < Rank[yroot]:
par[xroot] = yroot
elif Rank[xroot] > Rank[yroot]:
par[yroot] = xroot
else:
par[yroot] = xroot
Rank[xroot] += 1
# Function to compute minimum spanning tree
def compute_MST():
global ans
# Sort edges in increasing order of weight
edges.sort()
# Go through all the edges
for i in range(m):
u = find(edges[i][1][0])
v = find(edges[i][1][1])
if u == v:
continue
# Build minimum spanning tree
# and store minimum cost
mst.append(edges[i])
ans += edges[i][0]
union(u, v)
# Function to find the cost of minimum
# spanning tree
def modified_kruskal(x):
global ans
initialize()
# Make answer zero
ans = 0
sz = len(zeroes)
# Keep the edges which only have zero weights
# and remove all the other edges
for i in range(sz):
front = zeroes[0]
zeroes.popleft()
if front[0] == x[0] and front[1] == x[1]:
continue
# Make union between the vertices of
# edges which have weight zero and keep
# them in queue
union(front[0], front[1])
zeroes.append(front)
# Find the cost of the minimum spanning tree
for i in range(len(mst)):
u = find(mst[i][1][0])
v = find(mst[i][1][1])
if u == v:
continue
ans += mst[i][0]
union(u, v)
# Function to handle different queries
def query(type: int, u=0, v=0):
global ans
# Update edge weight to 0
if type == 2:
# push edge in zeros
zeroes.append((u, v))
modified_kruskal((-1, -1))
# Restore edge weight to original value
elif type == 3:
# push edge in zeros
zeroes.append((u, v))
modified_kruskal((u, v))
else:
print(ans)
# Driver Code
if __name__ == "__main__":
# Number of nodes and edges
n = 4
m = 4
initialize()
# Add edges
add_edge(1, 2, 1)
add_edge(2, 3, 1)
add_edge(3, 4, 1)
add_edge(4, 1, 1)
# Build the minimum spanning tree
compute_MST()
# Execute queries
query(2, 1, 2)
query(1)
query(3, 1, 2)
query(1)
# This code is contributed by
# sanjeev2552
using System;
using System.Collections.Generic;
class Program
{
const int N = 2005;
static int n, m, ans;
static int[] par = new int[N];
static int[] Rank = new int[N];
static List<Tuple<int, Tuple<int, int>>> edges = new List<Tuple<int, Tuple<int, int>>>();
static List<Tuple<int, Tuple<int, int>>> mst = new List<Tuple<int, Tuple<int, int>>>();
static Queue<Tuple<int, int>> zeroes = new Queue<Tuple<int, int>>();
static void Initialize()
{
// Initialize parent and rank arrays
for (int i = 0; i <= n; i++)
{
par[i] = i;
Rank[i] = 0;
}
}
static void AddEdge(int u, int v, int weight)
{
// Add edge to the list
edges.Add(new Tuple<int, Tuple<int, int>>(weight, new Tuple<int, int>(u, v)));
}
static int Find(int x)
{
// Find the root of the set using path compression
if (par[x] != x)
{
par[x] = Find(par[x]);
}
return par[x];
}
static void Union(int x, int y)
{
// Union by rank
int xroot = Find(x);
int yroot = Find(y);
if (Rank[xroot] < Rank[yroot])
{
par[xroot] = yroot;
}
else if (Rank[xroot] > Rank[yroot])
{
par[yroot] = xroot;
}
else
{
par[yroot] = xroot;
Rank[xroot]++;
}
}
static void ComputeMST()
{
ans = 0;
// Sort edges in increasing order of weight
edges.Sort();
for (int i = 0; i < m; i++)
{
int u = Find(edges[i].Item2.Item1);
int v = Find(edges[i].Item2.Item2);
if (u == v)
{
// Skip if adding the edge creates a cycle
continue;
}
// Build minimum spanning tree and update cost
mst.Add(edges[i]);
ans += edges[i].Item1;
Union(u, v);
}
}
static void ModifiedKruskal(Tuple<int, int> x)
{
Initialize();
ans = 0;
int sz = zeroes.Count;
for (int i = 0; i < sz; i++)
{
Tuple<int, int> front = zeroes.Dequeue();
if (front.Item1 == x.Item1 && front.Item2 == x.Item2)
{
continue;
}
Union(front.Item1, front.Item2);
zeroes.Enqueue(front);
}
for (int i = 0; i < mst.Count; i++)
{
int u = Find(mst[i].Item2.Item1);
int v = Find(mst[i].Item2.Item2);
if (u == v)
{
continue;
}
ans += mst[i].Item1;
Union(u, v);
}
}
static void Query(int type, int u = 0, int v = 0)
{
if (type == 2)
{
// Update edge weight to 0
zeroes.Enqueue(new Tuple<int, int>(u, v));
ModifiedKruskal(new Tuple<int, int>(-1, -1));
}
else if (type == 3)
{
// Restore edge weight to original value
zeroes.Enqueue(new Tuple<int, int>(u, v));
ModifiedKruskal(new Tuple<int, int>(u, v));
}
else
{
// Print the cost of the minimum spanning tree
Console.WriteLine(ans);
}
}
static void Main()
{
n = 4;
m = 4;
Initialize();
// Add edges
AddEdge(1, 2, 1);
AddEdge(2, 3, 1);
AddEdge(3, 4, 1);
AddEdge(4, 1, 1);
// Build the minimum spanning tree
ComputeMST();
// Execute queries
Query(2, 1, 2);
Query(1);
Query(3, 1, 2);
Query(1);
}
}
// JS implementation of the approach
const N = 2005;
let n = 0,
m = 0,
ans = 0;
// To store vertices, edges
// and the required answer
const par = new Array(N),
Rank = new Array(N),
edges = [],
mst = [],
zeroes = [];
// Function for initialize
function initialize() {
for (let i = 0; i <= n; i++) {
par[i] = i;
Rank[i] = 0;
}
}
// Function to add edges
function add_edge(u, v, weight) {
edges.push([weight, [u, v]]);
}
// Utility function to find set of an element i
// (uses path compression technique)
function find(x) {
if (par[x] !== x) {
par[x] = find(par[x]);
}
return par[x];
}
// Function that performs union of two sets x and y
// (uses union by rank)
function union(x, y) {
const xroot = find(x);
const yroot = find(y);
if (Rank[xroot] < Rank[yroot]) {
par[xroot] = yroot;
} else if (Rank[xroot] > Rank[yroot]) {
par[yroot] = xroot;
} else {
par[yroot] = xroot;
Rank[xroot]++;
}
}
// Function to compute minimum spanning tree
function compute_MST() {
// Sort edges in increasing order of weight
edges.sort((a, b) => a[0] - b[0]);
// Go through all the edges
for (let i = 0; i < m; i++) {
const u = find(edges[i][1][0]);
const v = find(edges[i][1][1]);
if (u === v) continue;
// Build minimum spanning tree
// and store minimum cost
mst.push(edges[i]);
ans += edges[i][0];
union(u, v);
}
}
// Function to find the cost of minimum
// spanning tree
function modified_kruskal(x) {
initialize();
// Make answer zero
ans = 0;
const sz = zeroes.length;
// Keep the edges which only have zero weights
// and remove all the other edges
for (let i = 0; i < sz; i++) {
const front = zeroes.shift();
if (front[0] === x[0] && front[1] === x[1]) continue;
// Make union between the vertices of
// edges which have weight zero and keep
// them in queue
union(front[0], front[1]);
zeroes.push(front);
}
// Find the cost of the minimum spanning tree
for (let i = 0; i < mst.length; i++) {
const u = find(mst[i][1][0]);
const v = find(mst[i][1][1]);
if (u === v) continue;
ans += mst[i][0];
union(u, v);
}
}
// Function to handle different queries
function query(type, u = 0, v = 0) {
// Update edge weight to 0
if (type === 2) {
// push edge in zeros
zeroes.push([u, v]);
modified_kruskal([-1, -1]);
}// Restore edge weight to original value
else if (type === 3) {
// push edge in zeros
zeroes.push([u, v]);
modified_kruskal([u, v]);
} else {
console.log(ans);
}
}
// Number of nodes and edges
n = 4;
m = 4;
initialize();
add_edge(1, 2, 1);
add_edge(2, 3, 1);
add_edge(3, 4, 1);
add_edge(4, 1, 1);
// Build the minimum spanning tree
compute_MST();
query(2, 1, 2);
query(1);
query(3, 1, 2);
query(1);
// This code is contributed by lokeshpotta20.
Output
2 3
Time Complexity: O(N) per query, where N is the total number of nodes in the graph.
Auxiliary Space: O(N)

