題目:給定一張$n$個點$m$條邊的無向圖,求無向圖的嚴格次小生成樹。
嚴格次小生成樹:設最小生成樹的邊權之和為$\mathrm$,嚴格次小生成樹就是指邊權之和大於$\mathrm$的生成樹中最小的乙個。
輸入格式: 第一行包含兩個整數$n$和$m$。 接下來$m$行,每行包含三個整數$x,y,z$,表示點$x$和點$y$之前存在一條邊,邊的權值為$z$。
輸出格式:包含一行,僅乙個數,表示嚴格次小生成樹的邊權和。(資料保證必定存在嚴格次小生成樹)
資料範圍:$n\leqslant 10^5,m\leqslant 3\times10^5$。
分析:我們先求出原圖的最小生成樹,然後列舉每一條非樹邊,看看當前兩點構成的路徑上最大邊與次大邊與該非樹邊的大小關係,由於求出的最小生成樹是選出的最短邊,因此非樹邊一定滿足大於等於這兩點路徑上的所有邊,當然也滿足大於等於最大邊。若等於最大邊,則我們將次大邊替換成非樹邊,否則替換最大邊為非樹邊。樹上兩點路徑上的最大邊與次大邊可以在求$\mathrm$時也求出來,具體地,我們設$g[x][y][0]$表示點$x$向上走$2^y$步中的次大邊,$g[x][y][1]$表示點$x$向上走$2^y$步中的最大邊。那麼我們可以先求出走到$2^$點的最大邊,然後再走$2^$步,對這兩步中的最大邊取最大值即可;對於次大邊,如果這兩個模組內的最大邊相等,則我們用這兩個模組的次大邊更新;如果第一階段的最大邊$>$第二階段的最大邊,那麼最大邊在第一階段的次大邊與第二階段的最大邊中取最大值,不然則反之。
#include #include#include
#include
#include
using
namespace
std;
using ll = long
long
;const
int n = 1e5+10, m = 3e5+10
;struct
node
}edge[m];
intn, m, p[n];
int h[n], e[n*2], ne[n*2], w[n*2
], idx;
int f[n][18], g[n][18][2
], d[n];
bool
st[m];
void add(int a, int b, int
c)int find(int
x)void merge(int c[2], int a[2], int b[2
])void bfs(int
u) }}}
}int lca(int res, int x, int
y) }
if(x==y) return
x;
for(int i=17; i>=0; i--)
}merge(res, res, g[x][
0]);
merge(res, res, g[y][
0]);
return f[x][0];}
int main(void
) }
bfs(1);
int delta =int_max;
for(int i=0; i)
}cout
return0;
}
AcWing 356 次小生成樹
一道蠻經典的題目,隨手記錄下。題目描述 給定一張 n 個點 m 條邊的無向圖,求無向圖的嚴格次小生成樹。設最小生成樹的邊權之和為sum,嚴格次小生成樹就是指邊權之和大於sum的生成樹中最小的乙個。注意本題所求的次小生成樹是嚴格次小的 題解 先用kruskal求出給定圖的最小生成樹,再列舉沒有被選上的...
AcWing 356 次小生成樹(lca)
給定一張 n 個點 m 條邊的無向圖,求無向圖的嚴格次小生成樹。設最小生成樹的邊權之和為sum,嚴格次小生成樹就是指邊權之和大於sum的生成樹中最小的乙個。第一行包含兩個整數n和m。接下來m行,每行包含三個整數x,y,z,表示點x和點y之前存在一條邊,邊的權值為z。包含一行,僅乙個數,表示嚴格次小生...
最小生成樹 次小生成樹
一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...