Skip to content

Commit 9e3ab18

Browse files
committed
feat: 20260312 check in
1 parent 8020b53 commit 9e3ab18

2 files changed

Lines changed: 143 additions & 0 deletions

File tree

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# 3600. 升级后最大生成树稳定性
2+
3+
> **日期**:2026-03-12
4+
> **所用时间**:45min
5+
> **知识点**:并查集、二分答案
6+
7+
## 1. 并查集 + 二分答案
8+
9+
### 题意与目标
10+
11+
- 无向图有 $n$ 个点、若干条边,每条边有**稳定性** $s$,且可能是**必选****可选**
12+
- 可以花费 1 次机会将某条可选边的稳定性从 $s$ 升级为 $2s$,最多升级 $k$ 次。
13+
- 求:在形成一棵生成树的前提下,**生成树中边的最小稳定性**(即树的稳定性)最大能是多少;若无法形成生成树则返回 $-1$。
14+
15+
### 思路概述
16+
17+
答案具有单调性:若稳定性 $x$ 能达到,则比 $x$ 更小的稳定性也能达到。因此可以**二分答案**:二分「最终生成树的最小稳定性」$mid$,用 `check(mid)` 判断:能否在至多 $k$ 次升级内,选边形成一棵生成树,且每条边的稳定性都 $\ge mid$。
18+
19+
二分范围:下界为所有边中最小的 $s$(`min_s`),上界为「某条边升级后的最大稳定性」$2 \cdot \max_s$,因此取 `[min_s, max_s * 2 + 1)` 即可(右开便于二分)。
20+
21+
### check(mid) 的逻辑
22+
23+
要判断「能否在至多 $k$ 次升级下,得到一棵稳定性均 $\ge mid$ 的生成树」,可以按边分类处理:
24+
25+
1. **必选边**
26+
- 若某条必选边的 $s < mid$,说明即使用上这条边,稳定性也达不到 $mid$,直接返回 `False`
27+
- 否则($s \ge mid$)必须加入生成树,在并查集中合并两端点。
28+
29+
2. **可选边**
30+
- $s \ge mid$:不升级也能用,直接加入并查集。
31+
- $s < mid \le 2s$:升级一次后稳定性变为 $2s \ge mid$,可以选用,但会消耗 1 次升级机会。
32+
- $mid > 2s$:升级后仍达不到 $mid$,不能选。
33+
34+
实现时可以先**第一遍扫所有边**:必选边若 $s < mid$ 则返回 `False`;否则对「必选边」或「$s \ge mid$ 的边」执行合并。再**第二遍扫所有边**:只处理可选边且 $s < mid \le 2s$ 的,在升级次数 $t \le k$ 且能合并(不形成环)时合并并 `t -= 1`。最后看并查集是否只剩一个连通分量(`u.cnt == 1`),是则说明能形成一棵满足条件的生成树。
35+
36+
### 主流程与预处理
37+
38+
- **无解**
39+
- 必选边成环(同一并查集里再合并必选边会失败)则无解。
40+
- 把所有边(必选+可选)都加入另一个并查集后,若图不连通(`all_uf.cnt > 1`)则无法形成生成树,也无解。
41+
- **有解**:在 `[min_s, max_s * 2 + 1)` 上二分最大的 $mid$ 使得 `check(mid)` 为真,该 $mid$ 即为答案。
42+
43+
### 复杂度分析
44+
45+
- **时间复杂度**:预处理并查集与最值 $O(E \cdot \alpha(V))$;二分 $O(\log S)$ 次,每次 `check` 遍历边并查集合并 $O(E \cdot \alpha(V))$,合计 $O(E \cdot \alpha(V) \cdot \log S)$,$S$ 为稳定性上界(如 `max_s * 2`)。
46+
- **空间复杂度**:并查集 $O(V)$,以及若干变量 $O(1)$。
47+
48+
**Python3**
49+
50+
```python
51+
class UnionFind:
52+
def __init__(self, n):
53+
self.fa = list(range(n))
54+
self.cnt = n
55+
56+
def find(self, x):
57+
if self.fa[x] != x:
58+
self.fa[x] = self.find(self.fa[x])
59+
return self.fa[x]
60+
61+
def merge(self, a, b):
62+
a, b = self.find(a), self.find(b)
63+
if a == b:
64+
return False
65+
self.fa[a] = b
66+
self.cnt -= 1
67+
return True
68+
69+
class Solution:
70+
def maxStability(self, n: int, edges: List[List[int]], k: int) -> int:
71+
all_uf = UnionFind(n)
72+
must_uf = UnionFind(n)
73+
min_s, max_s = inf, 0
74+
for x, y, s, must in edges:
75+
if must and not must_uf.merge(x, y):
76+
return -1
77+
all_uf.merge(x, y)
78+
min_s = min(min_s, s)
79+
max_s = max(max_s, s)
80+
81+
if all_uf.cnt > 1:
82+
return -1
83+
84+
def check(mid):
85+
u = UnionFind(n)
86+
for x, y, s, must in edges:
87+
if must and s < mid:
88+
return False
89+
if must or s >= mid:
90+
u.merge(x, y)
91+
92+
t = k
93+
for x, y, s, must in edges:
94+
if t == 0 or u.cnt == 1:
95+
break
96+
if not must and s < mid <= s * 2 and u.merge(x, y):
97+
t -= 1
98+
return u.cnt == 1
99+
100+
l, r = min_s, max_s * 2 + 1
101+
while l < r:
102+
mid = l + r + 1 >> 1
103+
if check(mid):
104+
l = mid
105+
else:
106+
r = mid - 1
107+
return r
108+
```
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# 3863. 将一个字符串排序的最小操作次数
2+
3+
> **日期**:2026-03-12
4+
> **所用时间**:3min
5+
> **知识点**:分类讨论
6+
7+
## 1. 贪心 + 分类讨论
8+
9+
若串已有序(任意相邻字符非严格递增)则答案为 0。若长度为 2 且无序,则无法在有限次操作内排好序,返回 -1。否则记全局最小字符为 `mi`、最大为 `mx`:若最小字符已在首位或最大字符已在末位,说明一次操作即可(把最小移到最前或把最大移到最后);若 `mi``mx` 出现在中间某个位置,则两次操作可完成;否则需要三次操作。
10+
11+
复杂度分析:
12+
13+
- 时间复杂度:$O(n)$
14+
- 空间复杂度:$O(1)$
15+
16+
**Python3**
17+
18+
```python
19+
class Solution:
20+
def minOperations(self, s: str) -> int:
21+
if all(x <= y for x, y in pairwise(s)):
22+
return 0
23+
24+
if len(s) == 2:
25+
return -1
26+
27+
mi, mx = min(s), max(s)
28+
if s[0] == mi or s[-1] == mx:
29+
return 1
30+
31+
if any(c in (mi, mx) for c in s[1:-1]):
32+
return 2
33+
34+
return 3
35+
```

0 commit comments

Comments
 (0)