You are given an integer n, representing n nodes numbered from 0 to n - 1 and a list of edges, where edges[i] = [u_i, v_i, s_i, must_i]:
u_i and v_i indicates an undirected edge between nodes u_i and v_i
s_i is the strength of the edge
must_i is an integer (0 or 1). If must_i == 1, the edge must be included in the spanning tree. These edges cannot be upgraded.
You are also given an integer k, the maximum number of upgrades you can perform. Each upgrade doubles the strength of an edge, and each eligible edge (with must_i == 0) can be upgraded at most once.
The stability of a spanning tree is defined as the minimum strength score among all edges included in it.
Return the maximum possible stability of any valid spanning tree. If it is impossible to connect all nodes, return -1.
Note: A spanning tree of a graph with n nodes is a subset of the edges that connects all nodes together (i.e. the graph is connected) without forming any cycles, and uses exactly n - 1 edges.
Input & Output
Example 1 — Basic Case
$Input:n = 4, edges = [[0,1,4,1],[1,2,2,0],[2,3,3,0],[0,3,5,0]], k = 2
›Output:6
💡 Note:We can upgrade edges [1,2] (2→4) and [2,3] (3→6). With mandatory edge [0,1] strength 4, we build spanning tree with edges (0,1,4), (0,3,5), (2,3,6). Minimum strength is 4, but if we use (0,1,4), (1,2,4), (2,3,6), minimum is 4. Actually, the optimal is to use edges that give stability 6.
Example 2 — No Upgrades Needed
$Input:n = 3, edges = [[0,1,10,0],[1,2,10,0],[0,2,1,1]], k = 1
›Output:1
💡 Note:Mandatory edge [0,2] has strength 1, so maximum stability is limited to 1 regardless of upgrades.
Example 3 — Impossible Case
$Input:n = 3, edges = [[0,1,5,0]], k = 1
›Output:-1
💡 Note:Only 1 edge but need 2 edges for spanning tree of 3 nodes. Impossible to connect all nodes.
Maximize Spanning Tree Stability with Upgrades — Solution
The key insight is to use binary search on the answer space - the stability value. For each candidate stability, we check if it's achievable by filtering edges that meet the threshold and greedily assigning upgrades. Best approach is Binary Search on Answer with Time: O(log(max_strength) × m log m), Space: O(m + n).
Common Approaches
✓
Binary Search on Answer
⏱️ Time: O(log(max_strength) × m log m)
Space: O(m + n)
Binary search on the answer space (minimum stability). For each candidate stability, check if we can build a valid spanning tree with that minimum edge strength using at most k upgrades.
Brute Force - Try All Combinations
⏱️ Time: O(C(m,k) × m log m)
Space: O(m + n)
Try every possible way to assign k upgrades to eligible edges, then for each combination find the maximum spanning tree (using maximum edge weights to maximize minimum). This approach explores the entire solution space.
Binary Search on Answer — Algorithm Steps
Binary search on possible stability values (0 to max possible strength)
For each candidate stability, filter edges that meet the threshold
Greedily assign upgrades to make more edges viable
Check if filtered edges can form spanning tree with mandatory edges
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Search Range
Binary search between 0 and max possible strength
2
Feasibility Check
For each mid value, check if spanning tree is possible
3
Narrow Range
Adjust search range based on feasibility result
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int *parent, *rank;
} UnionFind;
UnionFind* createUF(int n) {
UnionFind* uf = malloc(sizeof(UnionFind));
uf->parent = malloc(n * sizeof(int));
uf->rank = calloc(n, sizeof(int));
for (int i = 0; i < n; i++) uf->parent[i] = i;
return uf;
}
int find(UnionFind* uf, int x) {
if (uf->parent[x] != x) uf->parent[x] = find(uf, uf->parent[x]);
return uf->parent[x];
}
int unionSets(UnionFind* uf, int x, int y) {
int px = find(uf, x), py = find(uf, y);
if (px == py) return 0;
if (uf->rank[px] < uf->rank[py]) { int temp = px; px = py; py = temp; }
uf->parent[py] = px;
if (uf->rank[px] == uf->rank[py]) uf->rank[px]++;
return 1;
}
int compareEdges(const void* a, const void* b) {
int* edgeA = (int*)a;
int* edgeB = (int*)b;
return edgeB[2] - edgeA[2];
}
int canAchieveStability(int n, int edges[][4], int edgeCount, int k, int targetStability) {
int mandatoryEdges[100][3], mandatoryCount = 0;
int optionalWeak[100][3], weakCount = 0;
int optionalStrong[100][3], strongCount = 0;
for (int i = 0; i < edgeCount; i++) {
int u = edges[i][0], v = edges[i][1], s = edges[i][2], must = edges[i][3];
if (must == 1) {
if (s >= targetStability) {
mandatoryEdges[mandatoryCount][0] = u;
mandatoryEdges[mandatoryCount][1] = v;
mandatoryEdges[mandatoryCount][2] = s;
mandatoryCount++;
} else {
return 0;
}
} else {
if (s >= targetStability) {
optionalStrong[strongCount][0] = u;
optionalStrong[strongCount][1] = v;
optionalStrong[strongCount][2] = s;
strongCount++;
} else if (s * 2 >= targetStability) {
optionalWeak[weakCount][0] = u;
optionalWeak[weakCount][1] = v;
optionalWeak[weakCount][2] = s;
weakCount++;
}
}
}
UnionFind* uf = createUF(n);
int edgesUsed = 0;
for (int i = 0; i < mandatoryCount; i++) {
if (unionSets(uf, mandatoryEdges[i][0], mandatoryEdges[i][1])) {
edgesUsed++;
}
}
if (edgesUsed > n - 1) {
free(uf->parent);
free(uf->rank);
free(uf);
return 0;
}
qsort(optionalStrong, strongCount, sizeof(optionalStrong[0]), compareEdges);
for (int i = 0; i < strongCount && edgesUsed < n - 1; i++) {
if (unionSets(uf, optionalStrong[i][0], optionalStrong[i][1])) {
edgesUsed++;
}
}
if (edgesUsed < n - 1 && k > 0) {
qsort(optionalWeak, weakCount, sizeof(optionalWeak[0]), compareEdges);
int upgradesUsed = 0;
for (int i = 0; i < weakCount && edgesUsed < n - 1 && upgradesUsed < k; i++) {
if (unionSets(uf, optionalWeak[i][0], optionalWeak[i][1])) {
edgesUsed++;
upgradesUsed++;
}
}
}
int result = (edgesUsed == n - 1);
free(uf->parent);
free(uf->rank);
free(uf);
return result;
}
int solution(int n, int edges[][4], int edgeCount, int k) {
if (edgeCount == 0) return -1;
int maxStrength = 0;
for (int i = 0; i < edgeCount; i++) {
if (edges[i][2] * 2 > maxStrength) maxStrength = edges[i][2] * 2;
}
int left = 0, right = maxStrength;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (canAchieveStability(n, edges, edgeCount, k, mid)) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
int main() {
int n;
scanf("%d", &n);
char line[10000];
scanf(" %[^\n]", line);
int edges[100][4];
int edgeCount = 0;
char* ptr = line + 1;
while (*ptr && *ptr != ']') {
if (*ptr == '[') {
sscanf(ptr, "[%d,%d,%d,%d]", &edges[edgeCount][0], &edges[edgeCount][1],
&edges[edgeCount][2], &edges[edgeCount][3]);
edgeCount++;
}
ptr++;
}
int k;
scanf("%d", &k);
printf("%d\n", solution(n, edges, edgeCount, k));
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(log(max_strength) × m log m)
Binary search iterations times MST construction for feasibility check
n
2n
⚡ Linearithmic
Space Complexity
O(m + n)
Union-find structure and edge storage
n
2n
⚡ Linearithmic Space
8.9K Views
MediumFrequency
~45 minAvg. Time
234 Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.