严格次小生成树板子
严格次小生成树:
性质:
-
边权之和比最小生成树大,比其他生成树小
-
由最小生成树删除一条树边,加入一条非树边得到
解法:
-
枚举非树边(u,v):此时能删除的是(u,v)最小路径上的边
-
使用倍增法维护最小路径上的最大值和次大值(防止操作后生成树权值和最小生成树权值一样)
const int M =3e5+5;
int n,m;
int f[M];
struct node{
int u,v,w;
node(){}
node(int a,int b,int c){
u=a;v=b;w=c;
}
};
vector<node>a;
int find(int x){
if(f[x]!=x){
f[x]=find(f[x]);
}return f[x];
}
void merge(int x,int y){
if(find(x)!=find(y)){
f[find(x)]=find(y);
}
}
vector<pii>e[M];
int dep[M];
int vis[M];
int fa[M][30];
int st1[M][30];
int st2[M][30];
int ans = inf;
int sum = 0;
void dfs(int u,int Fa,int we){
fa[u][0]=Fa;
dep[u]=dep[Fa]+1;
st1[u][0]=we;
st2[u][0]=-inf;
for(int j=1;j<=29;j++){
fa[u][j]=fa[fa[u][j-1]][j-1];
st1[u][j]=max(st1[u][j-1],st1[fa[u][j-1]][j-1]);
st2[u][j]=max(st2[u][j-1],st2[fa[u][j-1]][j-1]);
if(st1[u][j-1]>st1[fa[u][j-1]][j-1]){
st2[u][j]=max(st2[u][j],st1[fa[u][j-1]][j-1]);
}
else if(st1[u][j-1]<st1[fa[u][j-1]][j-1]){
st2[u][j]=max(st2[u][j],st2[u][j-1]);
}
}
for(auto[v,w]:e[u]){
if(v==Fa)continue;
dfs(v,u,w);
}
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
for(int j=29;j>=0;j--){
if(dep[fa[u][j]]>=dep[v]){
u=fa[u][j];
}
if(u==v)return u;
}
for(int j=29;j>=0;j--){
if(fa[u][j]!=fa[v][j]){
u=fa[u][j];
v=fa[v][j];
}
}
return fa[u][0];
}
int work(int u,int to,int val){
int res= - inf;
for(int j = 29 ;j>=0;j--){
if(dep[fa[u][j]]>=dep[to]){
if(st1[u][j]!=val)res=max(res,st1[u][j]);
else res = max(res,st2[u][j]);
u=fa[u][j];
}
}
return res;
}
void solve(){
cin>>n>>m;
rep(i,1,n)f[i]=i;
rep(i,1,m){
int x,b,c;cin>>x>>b>>c;
a.pb(node(x,b,c));
}
sort(a.begin(),a.end(),[](node A,node B){return A.w<B.w;});
int id=0;
for(auto[u,v,w]:a){
if(find(u)==find(v)){id++;continue;}
vis[id]=1;
merge(u,v);
sum+=w;
e[u].pb({v,w});
e[v].pb({u,w});
id++;
}
dfs(1,0,0);
id=0;
for(auto[u,v,w]:a){
if(vis[id]){id++;continue;}
ans=min(ans,sum - work(u, lca(u,v) , w)+w);
ans=min(ans,sum - work(v, lca(u,v) , w)+w);
id++;
}
cout<<ans<<endl;
}

浙公网安备 33010602011771号