BZOJ 1977 [BeiJing2010组队]次小生成树 Tree
严格次小生成树。一开始没有特批一圈都相等的情况,一直WA,十分难受。
先生成最小生成树,枚举每条非树边,连上它构成一个环,拆掉环上树边中最大的一条(若和该边相等则次大的一条)换上这条。
用倍增维护一条链上的最大边和次大边,倍增跑lca同时找出环上最大边和次大边,看能否更新答案。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
typedef long long LL;
using namespace std;
const int maxn=100000+299;
const int maxm=300000*2+299;
int upp=0,tot,n,m,k,ecnt,fir[maxn],nxt[maxm],to[maxm],vis[maxn],fa[maxn];
int f[maxn][32],R[maxn];
LL st[maxn][32],stc[maxn][32],ans,rem,rec,val[maxm],anspre;
struct edge{
int u,v,w,is;
friend bool operator <(const edge&A,const edge&B) {
return A.w<B.w;
}
}e[maxm];
void add(int u,int v,int w) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=(LL)w;
nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=(LL)w;
}
void init() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
void kruskal() {
sort(e+1,e+m+1);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++) {
int u=e[i].u,v=e[i].v;
int fu=find(u),fv=find(v);
if(fu!=fv) {
e[i].is=1;
anspre+=e[i].w;
add(u,v,e[i].w);
tot++;
if(tot==n-1) break;
fa[fu]=fv;
}
}
}
void dfs(int x,int ff) {
f[x][0]=ff; R[x]=R[ff]+1;
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=ff){
st[to[i]][0]=val[i];
stc[to[i]][0]=val[i];
dfs(to[i],x);
}
}
void make_st() {
for(int i=1;i<=30;i++)
for(int j=1;j<=n;j++) {
f[j][i]=f[f[j][i-1]][i-1];
int u=st[j][i-1],v=st[f[j][i-1]][i-1];
st[j][i]=max(u,v);
if(u&&v&&u!=v) stc[j][i]=min(u,v);
if(stc[j][i-1]) stc[j][i]=max(stc[j][i],stc[j][i-1]);
if(stc[f[j][i-1]][i-1]) stc[j][i]=max(stc[j][i],stc[f[j][i-1]][i-1]);
}
}
int swapp(LL x,LL &zd,LL &cd) {
if(x==zd) return 0;
if(x>zd) {
cd=max(cd,zd);
zd=x;
}
else cd=max(cd,x);
}
int lca(int x,int y) {
rem=0,rec=0;
if(R[x]<R[y]) swap(x,y);
for(int i=30;i>=0;i--) {
if(R[f[x][i]]>=R[y]) {
if(rem&&st[x][i]>rem) rec=max(rem,rec);
rem=max(rem,st[x][i]);
if(i!=0) rec=max(rec,stc[x][i]);
x=f[x][i];
}
}
if(x==y) return 1;
for(int i=30;i>=0;i--) {
if(f[x][i]!=f[y][i]) {
swapp(stc[y][i],rem,rec);
swapp(stc[x][i],rem,rec);
swapp(st[x][i],rem,rec);
swapp(st[y][i],rem,rec);
x=f[x][i]; y=f[y][i];
}
}
swapp(stc[y][0],rem,rec);
swapp(stc[x][0],rem,rec);
swapp(st[x][0],rem,rec);
swapp(st[y][0],rem,rec);
return 1;
}
void work() {
ans=1e18;
for(int i=1;i<=m;i++) if(e[i].is!=1){
int x=e[i].u,y=e[i].v;
lca(x,y);
if(e[i].w!=rem) ans=min(ans,anspre-rem+e[i].w);
else if(e[i].w!=rec) ans=min(ans,anspre-rec+e[i].w);
}
printf("%lld\n",ans);
}
int main()
{
init();
kruskal();
dfs(1,0);
make_st();
work();
return 0;
}