题目描述:戳这里
题解:
求非严格次小生成树是比较简单的,但是严格的就有点(超级)麻烦了。
我们可以考虑一下用克鲁斯卡尔做最小生成树的过程,一定是找了一些最小的边来构造。
我们假设造好了最小生成树,那么任意一条没有被选择过的边加入树都会在树上形成一个环。
则我们只需要考虑取出当前环上权值最大的一条边,换成当前这条,看看是不是最小次大的就可以了。
但是题目中说了是严格次小生成树,所以有可能你当前的这条边和环上最大边权值相等,这样就比较尴尬了,但是我们如果不用这条边来修正答案有可能得不到最优解。
那么就可以考虑一下维护某一条链上的最大值和次大值(严格,意思就是次大值必须小于最大值),这样如果不能和最大值交换就和次大值交换,就可以维护这个严格次小值了。
但是怎样维护一条链上的最大值和次大值呢,我们可以考虑倍增维护,对于每一条非树边,只要对于它的两个顶点求一个lca,再直接倍增出最大值和次大值,修正一下答案就行了。
代码奇长无比,珂怕
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=100005,maxm=300005;
int n,m,tot,lnk[maxn],son[2*maxn],nxt[2*maxn],w[2*maxn],fa[maxn],dep[maxn];
int f[maxn][21],maxx[maxn][21],maxx1[maxn][21];
ll sum,ans;
struct dyt{
int x,y,w;
bool pd;
bool operator <(const dyt &b) const{return w<b.w;}
}a[maxm];
void add(int x,int y,int z){
son[++tot]=y,w[tot]=z,nxt[tot]=lnk[x],lnk[x]=tot;
}
int getfa(int x){if (fa[x]!=x) fa[x]=getfa(fa[x]); return fa[x];}
void dfs(int x,int las){
for (int j=lnk[x];j;j=nxt[j])
if (las!=son[j]) {
maxx[son[j]][0]=w[j]; f[son[j]][0]=x; dep[son[j]]=dep[x]+1;
dfs(son[j],x);
}
}
void make_(){
for (int j=1;j<=20;j++)
for (int i=1;i<=n;i++) {
f[i][j]=f[f[i][j-1]][j-1];
maxx[i][j]=max(maxx[i][j-1],maxx[f[i][j-1]][j-1]);
if (maxx[i][j-1]<maxx[i][j]) maxx1[i][j]=maxx[i][j-1];
if (maxx1[i][j-1]<maxx[i][j]&&maxx1[i][j-1]>maxx1[i][j]) maxx1[i][j]=maxx1[i][j-1];
if (maxx[f[i][j-1]][j-1]<maxx[i][j]&&maxx[f[i][j-1]][j-1]>maxx1[i][j]) maxx1[i][j]=maxx[f[i][j-1]][j-1];
if (maxx1[f[i][j-1]][j-1]<maxx[i][j]&&maxx1[f[i][j-1]][j-1]>maxx1[i][j]) maxx1[i][j]=maxx1[f[i][j-1]][j-1];
}
}
int get(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int j=20;j>=0;j--) if (dep[f[x][j]]>dep[y]) x=f[x][j];
if (dep[x]>dep[y]) x=f[x][0];
if (x==y) return y;
for (int j=20;j>=0;j--) if (f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
return f[x][0];
}
void doit(int x,int y,int g,int num){
int mx=0,mx1=0;
for (int j=20;j>=0;j--)
if (dep[f[x][j]]>=dep[g]) {
if (maxx[x][j]>mx){
mx1=mx,mx=maxx[x][j];
if (maxx1[x][j]>mx1) mx1=maxx1[x][j];
} else if (maxx[x][j]>mx1&&maxx[x][j]!=mx) mx1=maxx[x][j];
x=f[x][j];
}
for (int j=20;j>=0;j--)
if (dep[f[y][j]]>=dep[g]) {
if (maxx[y][j]>mx){
mx1=mx,mx=maxx[y][j];
if (maxx1[y][j]>mx1) mx1=maxx1[y][j];
} else if (maxx[y][j]>mx1&&maxx[y][j]!=mx) mx1=maxx[y][j];
y=f[y][j];
}
if (mx!=num) ans=min(ans,sum+num-mx); else ans=min(ans,sum+num-mx1);
}
int main(){
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++) fa[i]=i;
for (int i=1;i<=m;i++) scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].w);
sort(a+1,a+1+m);
for (int i=1;i<=m;i++) {
int fax=getfa(a[i].x),fay=getfa(a[i].y);
if (fax!=fay) {
fa[fax]=fay; a[i].pd=1; sum+=a[i].w;
add(a[i].x,a[i].y,a[i].w);
add(a[i].y,a[i].x,a[i].w);
}
}
dfs(1,0); make_(); ans=1e17;
for (int i=1;i<=m;i++)
if (!a[i].pd) {
int grand=get(a[i].x,a[i].y);
doit(a[i].x,a[i].y,grand,a[i].w);
}
printf("%lld\n",ans);
return 0;
}