原理简介
非严格次小生成树是在最小生成树有多棵时未被选为最小生成树的树,而严格最小生成树要求其边权和是第一个大于最小生成树的边权和。两者算法大致相同,都是枚举非树边加入树中,很明显会形成一棵基环树,在基环的环(不包含加入的边)中找出最大值被加入边代替更新答案,只是单纯找最大得到非严格,而找出第一个严格小于加入边权值的边得到的是严格次小生成树(被相同权值的边替换边权和不会变大哦~~~)。
例题Luogu-P4180
模板题
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
#define ll long long
#define rint register int
#define mid ((L + R) >> 1)
#define lson (x << 1)
#define rson (x << 1 | 1)
using namespace std;
template<typename xxx>inline void read(xxx &x) {
int f = 1;char c = getchar();x = 0;
for(;c ^ '-' && !isdigit(c);c = getchar());
if(c == '-') f = -1,c = getchar();
for(;isdigit(c);c = getchar()) x = (x<<3) + (x<<1) + (c ^ '0');
x *= f;
}
template<typename xxx>inline void print(xxx x) {
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9) print(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 1000010;
const int mod = 998244353;
const int inf = 0x7fffffff;
struct node{
int a,b;ll c;
}g[maxn];
inline bool gmp(node x,node y) {
return x.c < y.c;
}
struct edge {
int to,last;
ll val;
}e[maxn<<1];
int head[maxn],tot;
inline void add(int from,int to,ll val) {
++tot;
e[tot].to = to;
e[tot].val = val;
e[tot].last = head[from];
head[from] = tot;
}
int n,m,s;
int w[maxn],cnt;
int dad[maxn];
int dep[maxn];
int rev[maxn];
int seg[maxn];
int siz[maxn];
int son[maxn];
int top[maxn];
inline void ddfs1(int x,int da) {
siz[x] = 1;dad[x] = da;
dep[x] = dep[da] + 1;
for(rint i = head[x];i;i = e[i].last) {
if(e[i].to == da) continue;
ddfs1(e[i].to,x);
siz[x] += siz[e[i].to];
if(son[x] == 0 || siz[son[x]] < siz[e[i].to]) son[x] = e[i].to;
}
return ;
}
inline void ddfs2(int x,int tp) {
seg[x] = ++cnt;
rev[cnt] = x;
top[x] = tp;
if(!son[x]) return ;
ddfs2(son[x],tp);
for(rint i = head[x];i;i = e[i].last) {
if(e[i].to == dad[x] || e[i].to == son[x]) continue;
ddfs2(e[i].to,e[i].to);
}
return ;
}
ll sum,mks[maxn<<2],sec[maxn<<2];
inline void pushup(int x) {
mks[x] = max(mks[lson],mks[rson]);
if(mks[lson] == mks[rson]) sec[x] = max(sec[lson],sec[rson]);
else sec[x] = min(mks[lson],mks[rson]);
return ;
}
inline void update(int x,int L,int R,int pos,ll val) {
if(L == R) {
mks[x] = val;
sec[x] = -1e17;
return;
}
if(pos <= mid) update(lson,L,mid,pos,val);
else update(rson,mid + 1,R,pos,val);
pushup(x);
return ;
}
inline ll qmax(int x,int L,int R,int l,int r,ll val) {
if(l <= L && R <= r) {
if(val == mks[x]) return sec[x];
else return mks[x];
}
ll ans = 0;
if(l <= mid) ans = max(ans,qmax(lson,L,mid,l,r,val));
if(r > mid) ans = max(ans,qmax(rson,mid + 1,R,l,r,val));
return ans;
}
inline ll q1(int x,int y,ll val) {
ll ans = 0;
while(top[x] ^ top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x,y);
ans = max(ans,qmax(1,1,n,seg[top[x]],seg[x],val));
x = dad[top[x]];
}
if(x ^ y) {
if(dep[x] > dep[y]) swap(x,y);
ans = max(ans,qmax(1,1,n,seg[son[x]],seg[y],val));
}
return ans;
}
int fa[maxn];
inline int f(int x) {
while(x ^ fa[x]) x = fa[x] = fa[fa[x]];
return x;
}
int vis[maxn];
int main() {
ll cnm = 1e17;
read(n);read(m);
for(rint i = 1;i <= n; ++i) fa[i] = i;
for(rint i = 1;i <= m; ++i) {
read(g[i].a);
read(g[i].b);
read(g[i].c);
}
stable_sort(g + 1,g + m + 1,gmp);
for(rint i = 1;i <= m; ++i) {
int x = f(g[i].a);
int y = f(g[i].b);
if(x ^ y) {
fa[x] = y;sum += g[i].c;
add(g[i].a,g[i].b,g[i].c);
add(g[i].b,g[i].a,g[i].c);
} else {
vis[i] = 1;
}
}
ddfs1(1,0);
ddfs2(1,1);
for(rint i = 1;i <= m; ++i) {
if(!vis[i]) {
if(dep[g[i].a] > dep[g[i].b]) {
update(1,1,n,seg[g[i].a],g[i].c);
} else {
update(1,1,n,seg[g[i].b],g[i].c);
}
}
}
for(rint i = 1;i <= m; ++i) {
if(vis[i]) {
ll fk = q1(g[i].a,g[i].b,g[i].c);
ll tem = sum - fk + g[i].c;
if(tem ^ sum && tem < cnm) cnm = tem;
// cout<<tem<<" "<<sum<<" "<<fk<<endl;
}
}
print(cnm);
return 0;
}
/*
*/