之前写的一道题,突然看到就来发一篇博客。
大致思路就是首先找到最小生成树,再枚举每一条不在这个树里的边,加上后肯定就形成一个环,我们就要在这个环上断一条边。
新加的边 >= 这条路径上最大值。(反证法)
如果新加的边 > 这条路径上最大值,则ans - 最大值 + 新的权值,否则 - 次大值 + 新的值。
因此我们需要维护最大值,次大值即可。
以及,我的代码并不支持重边,提前筛掉。
下面是代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define int long long #define maxn 200010 #define inf 9999999999999999 int f[maxn][25],M[maxn][25],s[maxn][25],head[maxn]; int fa[maxn],dep[maxn],in[maxn*6],o[maxn]; int n,m,cnt,tot,MAX,SEC_MAX,ans=inf,size,map[1000][1000]; struct node { int to,nxt,w; } q[maxn*2]; struct K { int l,r,w,id; } k[maxn*6]; int find(int a) { return a==fa[a] ? a : fa[a]=find(fa[a]); } void add(int a,int b,int c) { q[++cnt].to=b; q[cnt].nxt=head[a]; head[a]=cnt; q[cnt].w=c; } bool cmp(K a,K b) { return a.w<b.w; } void Kruscal() { int num=0; for(int i=1; i<=m; i++) { int L=k[i].l; int R=k[i].r; int faL=find(L); int faR=find(R); if(faL==faR) continue; num++; fa[faL]=faR; add(k[i].l,k[i].r,k[i].w); add(k[i].r,k[i].l,k[i].w); in[k[i].id]=1; size+=k[i].w; if(num==n-1) break; } } void dfs(int u,int ff) { //cout<<u<<endl; dep[u]=dep[ff]+1; for(int i=0; i<=20; i++) { f[u][i+1]=f[f[u][i]][i]; M[u][i+1]=max(M[u][i],M[f[u][i]][i]); int sec1=min(M[u][i],M[f[u][i]][i]); int sec2=max(s[u][i],s[f[u][i]][i]); s[u][i+1]=max(sec1,sec2); } for(int i=head[u]; i; i=q[i].nxt) { int v=q[i].to; if(v==ff) continue; M[v][0]=q[i].w; f[v][0]=u; dfs(v,u); } } void Deal(int x,int i) { if(MAX!=M[x][i]) { if(MAX<M[x][i]) { SEC_MAX=max(MAX,s[x][i]); MAX=M[x][i]; } else SEC_MAX=max(SEC_MAX,M[x][i]); } } void DD(int x) { if(M[x][0]>MAX) { SEC_MAX=MAX; MAX=M[x][0]; } else if(M[x][0]>SEC_MAX) SEC_MAX=M[x][0]; } void LCA(int x,int y) { MAX=SEC_MAX=0; if(dep[x]<dep[y]) swap(x,y); for(int i=20; i>=0; i--) { if(dep[f[x][i]]>=dep[y]) { Deal(x,i); x=f[x][i]; } if(x==y) return ; } for(int i=20; i>=0; i--) { if(f[x][i]!=f[y][i]) { Deal(x,i); Deal(y,i); x=f[x][i]; y=f[y][i]; } } //cout<<SEC_MAX<<" "<<MAX<<" "; DD(x); DD(y); return ; } void SEC_Kruscal() { for(int i=1; i<=m; i++) { if(in[k[i].id]) continue; int x=k[i].l,y=k[i].r; int W=k[i].w; LCA(x,y); if(W==MAX) ans=min(ans,size-SEC_MAX+W); else ans=min(ans,size-MAX+W); //cout<<k[i].l<<" "<<k[i].r<<" "<<SEC_MAX<<" "<<MAX<<endl; } printf("%lld ",ans); } main() { scanf("%lld%lld",&n,&m); //if(n==7) {printf("242 ");return 0;} for(int i=1; i<=n; i++) fa[i]=i; for(int i=1; i<=m; i++) { int a,b,c; scanf("%lld%lld%lld",&a,&b,&c); k[++tot].l=a; k[tot].r=b; k[tot].w=c; k[tot].id=tot; } sort(k+1,k+m+1,cmp); Kruscal(); //for(int i=1;i<=m;i++) //printf("%d %d ",k[i].w,in[k[i].id]); dfs(1,0); SEC_Kruscal(); //cout<<s[3][0]<<endl; return 0; }