@@ -1497,8 +1497,8 @@ func (*graph) mstKruskal(in io.Reader, n, m int) int64 {
1497
1497
cntE := 0
1498
1498
for _ , e := range edges {
1499
1499
if fv , fw := find (e .v ), find (e .w ); fv != fw {
1500
- sum += int64 (e .wt )
1501
1500
fa [fv ] = fw
1501
+ sum += int64 (e .wt )
1502
1502
cntE ++
1503
1503
}
1504
1504
}
@@ -1701,14 +1701,128 @@ func (*graph) limitDegreeMST(dis [][]int, root, lim int) int {
1701
1701
return mstSum
1702
1702
}
1703
1703
1704
- // 次小生成树 Second best Minimum Spanning Tree
1705
- // todo 非严格/严格
1706
- // Using Kruskal and Lowest Common Ancestor
1707
- // https://oi-wiki.org/graph/mst/#_9
1704
+ // 严格次小生成树 Second best Minimum Spanning Tree
1705
+ // https://oi-wiki.org/graph/mst/#_13
1708
1706
// https://cp-algorithms.com/graph/second_best_mst.html
1709
- // todo 模板题 https://www.luogu.com.cn/problem/P4180
1710
- func (* graph ) secondMST (n , m int ) (sum int64 ) {
1711
- return
1707
+ // 模板题(严格)https://www.luogu.com.cn/problem/P4180 https://www.acwing.com/problem/content/358/
1708
+ // 注:非严格次小生成树
1709
+ // 做法更加简单,维护路径最大值即可,见 https://oi-wiki.org/graph/mst/#_10
1710
+ func (* graph ) strictlySecondMST (n int , edges []struct { v , w , wt int }, min , max func (int , int ) int ) int {
1711
+ sort .Slice (edges , func (i , j int ) bool { return edges [i ].wt < edges [j ].wt })
1712
+
1713
+ fa := make ([]int , n )
1714
+ for i := range fa {
1715
+ fa [i ] = i
1716
+ }
1717
+ var find func (int ) int
1718
+ find = func (x int ) int {
1719
+ if fa [x ] != x {
1720
+ fa [x ] = find (fa [x ])
1721
+ }
1722
+ return fa [x ]
1723
+ }
1724
+
1725
+ mstSum := 0 // int64
1726
+ inMST := make ([]bool , len (edges ))
1727
+ type nb struct { to , wt int }
1728
+ g := make ([][]nb , n )
1729
+ for i , e := range edges {
1730
+ v , w , wt := e .v , e .w , e .wt
1731
+ if fv , fw := find (v ), find (w ); fv != fw {
1732
+ fa [fv ] = fw
1733
+ mstSum += wt
1734
+ inMST [i ] = true
1735
+ g [v ] = append (g [v ], nb {w , wt }) // MST
1736
+ g [w ] = append (g [w ], nb {v , wt })
1737
+ }
1738
+ }
1739
+
1740
+ const mx = 17
1741
+ type pair struct { p , fi , se int }
1742
+ pa := make ([][mx ]pair , n )
1743
+ dep := make ([]int , n )
1744
+ var build func (v , p , d int )
1745
+ build = func (v , p , d int ) {
1746
+ pa [v ][0 ].p = p
1747
+ dep [v ] = d
1748
+ for _ , e := range g [v ] {
1749
+ if w := e .to ; w != p {
1750
+ pa [w ][0 ].fi = e .wt
1751
+ build (w , v , d + 1 )
1752
+ }
1753
+ }
1754
+ }
1755
+ build (0 , - 1 , 0 )
1756
+
1757
+ merge := func (xFi , xSe , yFi , ySe int ) (int , int ) {
1758
+ fi , se := max (xFi , yFi ), 0
1759
+ if xFi == yFi {
1760
+ se = max (xSe , ySe )
1761
+ } else if xFi > yFi {
1762
+ se = max (xSe , yFi )
1763
+ } else {
1764
+ se = max (xFi , ySe )
1765
+ }
1766
+ return fi , se
1767
+ }
1768
+ for i := 0 ; i + 1 < mx ; i ++ {
1769
+ for v := range pa {
1770
+ if p := pa [v ][i ]; p .p != - 1 {
1771
+ pp := pa [p.p ][i ]
1772
+ fi , se := merge (p .fi , p .se , pp .fi , pp .se )
1773
+ pa [v ][i + 1 ] = pair {pp .p , fi , se }
1774
+ } else {
1775
+ pa [v ][i + 1 ].p = - 1
1776
+ }
1777
+ }
1778
+ }
1779
+
1780
+ // 返回路径最大边权和严格次大边权
1781
+ queryPath := func (v , w int ) (fi , se int ) {
1782
+ if dep [v ] > dep [w ] {
1783
+ v , w = w , v
1784
+ }
1785
+ for i := 0 ; i < mx ; i ++ {
1786
+ if (dep [w ]- dep [v ])>> i & 1 > 0 {
1787
+ p := pa [w ][i ]
1788
+ fi , se = merge (fi , se , p .fi , p .se )
1789
+ w = p .p
1790
+ }
1791
+ }
1792
+ if w != v {
1793
+ for i := mx - 1 ; i >= 0 ; i -- {
1794
+ if pv , pw := pa [v ][i ], pa [w ][i ]; pv .p != pw .p {
1795
+ fi , se = merge (fi , se , pv .fi , pv .se )
1796
+ fi , se = merge (fi , se , pw .fi , pw .se )
1797
+ v , w = pv .p , pw .p
1798
+ }
1799
+ }
1800
+ fi , se = merge (fi , se , pa [v ][0 ].fi , pa [v ][0 ].se )
1801
+ fi , se = merge (fi , se , pa [w ][0 ].fi , pa [w ][0 ].se )
1802
+ }
1803
+ return
1804
+ }
1805
+
1806
+ const inf int = 1e9 // 1e18
1807
+ delta := inf
1808
+ for i , e := range edges {
1809
+ v , w , wt := e .v , e .w , e .wt
1810
+ if inMST [i ] || v == w { // 注意跳过自环
1811
+ continue
1812
+ }
1813
+ fi , se := queryPath (v , w )
1814
+ if wt > fi {
1815
+ delta = min (delta , wt - fi ) // 替换从而得到更大的 MST,取最小的替换差值
1816
+ } else if se > 0 { // 此时必然有 wt == fi
1817
+ delta = min (delta , wt - se ) // wt = fi > se,同样可以替换
1818
+ }
1819
+ }
1820
+ if delta == inf {
1821
+ return - 1
1822
+ }
1823
+ mstSum += delta
1824
+
1825
+ return mstSum
1712
1826
}
1713
1827
1714
1828
// Kruskal 重构树
0 commit comments