严格最小生成树
Posted thomastine
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了严格最小生成树相关的知识,希望对你有一定的参考价值。
原理简介
非严格次小生成树是在最小生成树有多棵时未被选为最小生成树的树,而严格最小生成树要求其边权和是第一个大于最小生成树的边权和。两者算法大致相同,都是枚举非树边加入树中,很明显会形成一棵基环树,在基环的环(不包含加入的边)中找出最大值被加入边代替更新答案,只是单纯找最大得到非严格,而找出第一个严格小于加入边权值的边得到的是严格次小生成树(被相同权值的边替换边权和不会变大哦~~~)。
例题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;
}
/*
*/
以上是关于严格最小生成树的主要内容,如果未能解决你的问题,请参考以下文章
luogu P4180 模板严格次小生成树[BJWC2010]