这是严格次小生成树的模板题~~
我们首先考虑非严格次小生成树(看这篇):
可以证明,只要更改原图一条边就是满足条件的最优解:
首先我们假设加入一条边E,则最小生成树上形成了一个环,贪心的想法,我们会选择环中最长的一边替换掉
假如再添加一条边E_(显然E_>=E)
- 若E_不在该环中,由于原图已为最小生成树,答案绝不会变小
- 若E_在该环中,由于E_>=E,答案也不会变好
这样就证明了只需替换一条边
接下来考虑如何快速找出环上的最大边
显然可以分成两段:
x———–>LCA(x,y)
y———–>LCA(x,y)
既然都扯上LCA了,那么在LCA同时顺便刷答案即可
就像这样:
void DFS(int x,int da,int va){
dep[x]=dep[da]+1,up[x][0]=da,p[x][0]=va;
for(int i=1;(1<<i)<=dep[x];i++) up[x][i]=up[up[x][i-1]][i-1],p[x][i]=Max(p[x][i-1],p[up[x][i-1]][i-1]);
for(int j=lnk[x];j;j=nxt[j]) if(son[j]!=da) DFS(son[j],x,w[j]);
}
int LCA(int x,int y){
int now=0;
if(dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y]) now=Max(now,p[x][pow[dep[x]-dep[y]]-1]),x=up[x][pow[dep[x]-dep[y]]-1];
if(x==y) return now;
for(int k=pow[dep[x]];k>=0;k--)if(up[x][k]!=up[y][k])
now=Max(Max(p[x][k],p[y][k]),now),x=up[x][k],y=up[y][k];
return Max(Max(p[x][0],p[y][0]),now);
}
再考虑如何求严格的。。
即当环中最大边==添入的边时,该怎么办
还是贪心想法,取严格次大边呗!
不过写起来真心爽
预处理:
#define Up up[x][i-1]
int dep[maxn],up[maxn][Log],val[maxn][Log],vll[maxn][Log];//val最大,vll严格次大
void DFS(int x,int dad){
dep[x]=dep[dad]+1,up[x][0]=dad;
for(__R int i=1;Pow[i]+1<=dep[x];i++){
up[x][i]=up[Up][i-1];
if(val[x][i-1]>val[Up][i-1]){
val[x][i]=val[x][i-1];
vll[x][i]=(vll[x][i-1]>val[Up][i-1]?vll[x][i-1]:val[Up][i-1]);//此时vll[x][i-1]!=val[x][i-1]且val[Up][i-1]!=val[x][i-1](val[Up][i-1]<val[x][i-1])
}else{
val[x][i]=val[Up][i-1];
if(vll[Up][i-1]>=val[x][i-1]) vll[x][i]=vll[Up][i-1];//vll[Up][i-1]必!=val[Up][i-1]
else if(val[x][i-1]!=val[x][i]) vll[x][i]=val[x][i-1];//严格
else vll[x][i]=(vll[x][i-1]>vll[Up][i-1]?vll[x][i-1]:vll[Up][i-1]);//vll显然是严格小于的
}
}
for(__R int j=lnk[x];j;j=nxt[j])if(son[j]!=dad) val[son[j]][0]=w[j],vll[son[j]][0]=INF,DFS(son[j],x);
}
询问比较简单(copy地巨爽)
int LCA(int x,int y,int p){
int D=INF,t;
if(dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y]){
if(val[x][t=LoG[dep[x]-dep[y]]-1]!=p) D=val[x][t]>D?val[x][t]:D;else D=vll[x][t]>D?vll[x][t]:D;
x=up[x][t];
}
if(x==y) return D;
for(__R int k=LoG[dep[x]]-1;k>=0;k--)if(up[x][k]!=up[y][k]){
if(val[x][k]!=p) D=val[x][k]>D?val[x][k]:D;else D=vll[x][k]>D?vll[x][k]:D;
if(val[y][k]!=p) D=val[y][k]>D?val[y][k]:D;else D=vll[y][k]>D?vll[y][k]:D;
x=up[x][k],y=up[y][k];
}
__R int k=0;
if(val[x][k]!=p) D=val[x][k]>D?val[x][k]:D;else D=vll[x][k]>D?vll[x][k]:D;
if(val[y][k]!=p) D=val[y][k]>D?val[y][k]:D;else D=vll[y][k]>D?vll[y][k]:D;
return D;
}
然后就可以了。。
复杂度
O(N∗logN+E∗logN)
O
(
N
∗
l
o
g
N
+
E
∗
l
o
g
N
)
#include<bits/stdc++.h>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define Up up[x][i-1]
#define LL long long
#define __R register
using namespace std;
static char buf[1000000],*p1=buf,*p2=buf;
const int maxE=(3e5)+5,maxn=(1e5)+5,Log=22,INF=-(2e9);
int n,m,fa[maxn],Pow[Log+5],LoG[maxn];bool vis[maxE];LL Ans=(LL)1<<60,S;
int tot,son[maxn<<1],nxt[maxn<<1],w[maxn<<1],lnk[maxn];
void add_e(int x,int y,int z){son[++tot]=y,w[tot]=z,nxt[tot]=lnk[x],lnk[x]=tot;}
struct Edges{
int x,y,w;
bool operator <(const Edges b)const{return w<b.w;}
}E[maxE];
int read(){
int ret=0;char ch=gt();
while(ch<'0'||ch>'9') ch=gt();
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
return ret;
}
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
int dep[maxn],up[maxn][Log],val[maxn][Log],vll[maxn][Log];//val最大,vll严格次大
void DFS(int x,int dad){
dep[x]=dep[dad]+1,up[x][0]=dad;
for(__R int i=1;Pow[i]+1<=dep[x];i++){
up[x][i]=up[Up][i-1];
if(val[x][i-1]>val[Up][i-1]){
val[x][i]=val[x][i-1];
vll[x][i]=(vll[x][i-1]>val[Up][i-1]?vll[x][i-1]:val[Up][i-1]);//此时vll[x][i-1]!=val[x][i-1]且val[Up][i-1]!=val[x][i-1](val[Up][i-1]<val[x][i-1])
}else{
val[x][i]=val[Up][i-1];
if(vll[Up][i-1]>=val[x][i-1]) vll[x][i]=vll[Up][i-1];//vll[Up][i-1]必!=val[Up][i-1]
else if(val[x][i-1]!=val[x][i]) vll[x][i]=val[x][i-1];//严格
else vll[x][i]=(vll[x][i-1]>vll[Up][i-1]?vll[x][i-1]:vll[Up][i-1]);//vll显然是严格小于的
}
}
for(__R int j=lnk[x];j;j=nxt[j])if(son[j]!=dad) val[son[j]][0]=w[j],vll[son[j]][0]=INF,DFS(son[j],x);
}
int LCA(int x,int y,int p){
int D=INF,t;
if(dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y]){
if(val[x][t=LoG[dep[x]-dep[y]]-1]!=p) D=val[x][t]>D?val[x][t]:D;else D=vll[x][t]>D?vll[x][t]:D;
x=up[x][t];
}
if(x==y) return D;
for(__R int k=LoG[dep[x]]-1;k>=0;k--)if(up[x][k]!=up[y][k]){
if(val[x][k]!=p) D=val[x][k]>D?val[x][k]:D;else D=vll[x][k]>D?vll[x][k]:D;
if(val[y][k]!=p) D=val[y][k]>D?val[y][k]:D;else D=vll[y][k]>D?vll[y][k]:D;
x=up[x][k],y=up[y][k];
}
__R int k=0;
if(val[x][k]!=p) D=val[x][k]>D?val[x][k]:D;else D=vll[x][k]>D?vll[x][k]:D;
if(val[y][k]!=p) D=val[y][k]>D?val[y][k]:D;else D=vll[y][k]>D?vll[y][k]:D;
return D;
}
int main(){
n=read(),m=read();
for(__R int i=1;i<=m;i++) E[i]=(Edges){read(),read(),read()};sort(E+1,E+1+m);
for(__R int i=0;(Pow[i]=1<<i)<=n;i++);
for(__R int i=1;i<=n;i++) LoG[i]=LoG[i-1]+(Pow[LoG[i-1]]==i),fa[i]=i;
for(__R int i=1,fx,fy;i<=m;i++)if((fx=getfa(E[i].x))!=(fy=getfa(E[i].y))){
fa[fx]=fy,S+=E[i].w,vis[i]=1;
add_e(E[i].x,E[i].y,E[i].w),add_e(E[i].y,E[i].x,E[i].w);
}
DFS(1,0);
LL now;
for(__R int i=1;i<=m;i++) if(!vis[i]&&(now=S-LCA(E[i].x,E[i].y,E[i].w)+E[i].w)<Ans) Ans=now;
printf("%lld\n",Ans);
return 0;
}