传送门:luoguP4180
题解
直接枚举所有不在最小生成数上的边,替代它的两个端点之间的路径上的严格小于这条边边权的边权最大的一条边。因为保证有解,最后取 m i n min min即可。
数据有点水,LCA写错都有90。。。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
int n,m,fa[N],bin[30],dep[N],f[N][20],d[N][20],fd[N][20];
int head[N],nxt[N<<1],to[N<<1],w[N<<1],tot;
ll ans,mx;
struct L{
int u,v,w,usd;
inline void ini(){scanf("%d%d%d",&u,&v,&w);}
bool operator <(const L&ky)const{return w<ky.w;}
}le[N*3];
int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
inline void lk(int u,int v,int vv)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;}
inline void upp(int x,int p,int vv)
{
if(vv>d[x][p]) {fd[x][p]=d[x][p];d[x][p]=vv;}
else if(vv<d[x][p] && vv>fd[x][p]) fd[x][p]=vv;
}
void dfs(int x)
{
int i,j;
for(i=1;bin[i]<=dep[x];++i){
f[x][i]=f[f[x][i-1]][i-1];
d[x][i]=d[x][i-1];fd[x][i]=fd[x][i-1];
upp(x,i,d[f[x][i-1]][i-1]);upp(x,i,fd[f[x][i-1]][i-1]);
}
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==f[x][0]) continue;
f[j][0]=x;dep[j]=dep[x]+1;d[j][0]=w[i];dfs(j);
}
}
inline int ask(int x,int y,int lim)
{
if(dep[x]<dep[y]) swap(x,y);
int i,j,cg=dep[x]-dep[y],re=-1;
for(i=0;bin[i]<=cg;++i)if(bin[i]&cg){
if(lim==d[x][i]) re=max(re,fd[x][i]);
else re=max(re,d[x][i]);
x=f[x][i];
}
if(x==y) return re;
for(i=16;~i;--i) if(f[x][i]!=f[y][i]){
if(lim==d[x][i]) re=max(re,fd[x][i]);
else re=max(re,d[x][i]);
if(lim==d[y][i]) re=max(re,fd[y][i]);
else re=max(re,d[y][i]);
x=f[x][i];y=f[y][i];
}
if(lim==d[x][0]) re=max(re,fd[x][0]);
else re=max(re,d[x][0]);
if(lim==d[y][0]) re=max(re,fd[y][0]);
else re=max(re,d[y][0]);
return re;
}
int main(){
memset(d,0x8f,sizeof(d));memset(fd,0x8f,sizeof(fd));
int i,j,x,y;bin[0]=1;
scanf("%d%d",&n,&m);
for(i=1;i<30;++i) bin[i]=bin[i-1]<<1;
for(i=1;i<=n;++i) fa[i]=i;
for(i=1;i<=m;++i) le[i].ini();
sort(le+1,le+m+1);
for(i=1,j=1;j<n;++i){
x=getfa(le[i].u);y=getfa(le[i].v);
if(x==y) continue;fa[x]=y;le[i].usd=1;mx+=le[i].w;j++;
lk(le[i].u,le[i].v,le[i].w);lk(le[i].v,le[i].u,le[i].w);
}
dfs(1);ans=1e18;
for(i=1;i<=m;++i) if(!le[i].usd){
j=ask(le[i].u,le[i].v,le[i].w);
if(j>=0) ans=min(ans,mx+le[i].w-j);
}
printf("%lld",ans);
return 0;
}