严格次小生成树 最小生成树+树上倍增
一定要注意是严格次小!!。。。
Solution:
相信大家不难想到:
先做一遍最小生成树,然后枚举剩下的边,然后在树上倍增,把最大的那条边给去掉,把这条给加上,全局取min。
然后你会发现你开心的交完后,只有80。
I:诶诶诶,怎么回事,明明是没错的啊。再看看。。。
某神ben:你好呆( ̄_, ̄ )看了题目没。。。
I:略略略,溜了溜了。。
好吧,这个题唯一需要注意的就是:严格次小!严格次小!严格次小!
这意味着:
不仅需要维护最大值的倍增数组,还需要维护次大值的倍增数组。
Code↓:
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;
IL int gi() {
char ch=getchar(); RG int x=0,w=0;
while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();}
while (ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
return w?-x:x;
}
const int N=1e5+10;
const int M=3e5+10;
LL sum,Ans=1e18;
int n,m,tot,head[N],fa[N],tag[M],dep[N],f[N][21],g[N][21],t[N][21];
struct Edge{int x,y,z;}e[M];
struct EDGE{int next,to,v;}E[N<<1];
IL bool cmp(Edge A,Edge B) {return A.z<B.z;}
IL void make(int a,int b,int c) {
E[++tot]=(EDGE){head[a],b,c},head[a]=tot;
E[++tot]=(EDGE){head[b],a,c},head[b]=tot;
}
IL int getfa(int x) {return x==fa[x]?x:fa[x]=getfa(fa[x]);}
IL void Kruskal() {
RG int i,x,y,fx,fy,num=0;
sort(e+1,e+m+1,cmp);
for (i=1;i<=n;++i) fa[i]=i;
for (i=1;i<=m;++i) {
x=e[i].x,y=e[i].y,fx=getfa(x),fy=getfa(y);
if (fx!=fy) {
tag[i]=1,fa[fx]=fy,sum+=e[i].z,make(x,y,e[i].z);
if (++num==n-1) break;
}
}
}
void dfs(int x,int fx) {
RG int i,y;
for (i=head[x],dep[x]=dep[fx]+1;i;i=E[i].next)
if ((y=E[i].to)!=fx) f[y][0]=x,g[y][0]=E[i].v,dfs(y,x);
}
IL void work() {
RG int i,j,p;
for (i=1;i<=20;++i)
for (j=1;j<=n;++j) {
p=f[j][i-1],f[j][i]=f[p][i-1];
if (g[j][i-1]>g[p][i-1]) g[j][i]=g[j][i-1],t[j][i]=max(g[p][i-1],t[j][i-1]);
if (g[j][i-1]<g[p][i-1]) g[j][i]=g[p][i-1],t[j][i]=max(g[j][i-1],t[p][i-1]);
if (g[j][i-1]==g[p][i-1]) g[j][i]=g[p][i-1],t[j][i]=max(t[j][i-1],t[p][i-1]);
}
}
IL int getMax(int x,int y,int ver) {
RG int i,ans=0;
if (dep[x]<dep[y]) swap(x,y);
for (i=20;i>=0;--i)
if (dep[f[x][i]]>=dep[y]) {
if (g[x][i]<ver) ans=max(ans,g[x][i]);
x=f[x][i];
}
if (x==y) return ans;
for (i=20;i>=0;--i)
if (f[x][i]!=f[y][i]) {
if (g[x][i]<ver) ans=max(ans,g[x][i]);
if (g[y][i]<ver) ans=max(ans,g[y][i]);
x=f[x][i],y=f[y][i];
}
if (g[x][0]<ver) ans=max(ans,g[x][0]);
if (g[y][0]<ver) ans=max(ans,g[y][0]);
return ans;
}
int main()
{
RG int i,now;
n=gi(),m=gi();
for (i=1;i<=m;++i) e[i].x=gi(),e[i].y=gi(),e[i].z=gi();
Kruskal(),dfs(1,0),work();
for (i=1;i<=m;++i)
if (!tag[i]) {
now=getMax(e[i].x,e[i].y,e[i].z);
Ans=min(Ans,sum+e[i].z-now);
}
printf("%lld\n",Ans);
return 0;
}
// 严格次小 不能相等啊...