original link - https://www.luogu.org/problem/P4180
题意:
给出一个图,求严格次小生成树,即边权和严格小于 M S T MST MST。
解析:
定理: 若存在次小生成树,则必然存在一个次小生成树与 M S T MST MST只有一条边的差异。
所以我们先做一遍 M S T MST MST,然后去判断每条边加进去后的情况。显然加进去后形成一个环,要在环上原来的边中删除一条边(若边为 ( a , b ) (a,b) (a,b),则要删除的边在 ( a , b ) (a,b) (a,b)的路径上)。
根据要求,我们应该删除不等于 v a l ( a , b ) val(a,b) val(a,b)的最大的边,所以我们要预处理路径上的最大值和次大值。
这个可以用 L C A LCA LCA加倍增做,分成 ( a , l c a ) ( b , l c a ) (a,lca)(b,lca) (a,lca)(b,lca)两条链,再由倍增分成多个区间。最后合并一下就可以得出答案值 v a l val val了。
最后的答案为 M S T − v a l + v a l ( a , b ) MST-val+val(a,b) MST−val+val(a,b)。
自己检查了一遍,中间过程确实不存在爆int范围的计算,但是用int就是WA。无奈将所有与边权有关的都改为long long
代码:
/*
* Author : Jk_Chen
* Date : 2019-08-22-09.46.14
*/
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<
const LL mod=1e9+7;
const int maxn=1e5+9;
LL rd() {
LL ans=0;
char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))
last=ch,ch=getchar();
while(ch>='0' && ch<='9')
ans=ans*10+ch-'0',ch=getchar();
if(last=='-')
ans=-ans;
return ans;
}
/*_________________________________________________________head*/
#define rep_e(i,p,u) for(int i=head[p],u=to[i];i;i=nex[i],u=to[i])
int head[maxn],to[maxn<<1],nex[maxn<<1],now;
LL val[maxn<<1];
void add(int a,int b,LL v) {
nex[++now]=head[a];
head[a]=now;
to[now]=b;
val[now]=v;
}
void init_edge() {
memset(head,0,sizeof head);
now=0;
}
/*_________________________________________________________edge*/
const LL inf=1e18;
int deep[maxn];
int pa[maxn][32];
LL mx[maxn][32],mxx[maxn][32];
void dfs(int p,int f,int t) {
pa[p][0]=f;
deep[p]=t;
rep_e(i,p,u) {
if(u!=f) {
mx[u][0]=val[i];
mxx[u][0]=-inf;
dfs(u,p,t+1);
}
}
}
void init(int n) {
for(int i=1; (1<<i)<=n; i++) {
for(int j=1; j<=n; j++) {
pa[j][i]=pa[pa[j][i-1]][i-1];
mx[j][i]=max(mx[j][i-1],mx[pa[j][i-1]][i-1]);
mxx[j][i]=max(mxx[j][i-1],mxx[pa[j][i-1]][i-1]);
if(mx[j][i-1]>mx[pa[j][i-1]][i-1])
mxx[j][i]=max(mxx[j][i],mx[pa[j][i-1]][i-1]);
else if(mx[j][i-1]<mx[pa[j][i-1]][i-1]) // 严格次小
mxx[j][i]=max(mxx[j][i],mx[j][i-1]);
}
}
}
int lca(int a,int b) {
if(deep[a]>deep[b])
swap(a,b);
int i;
for(i=0; (1<<i)<deep[b]; i++)
;
i--;
for(;;) {
if(deep[a]==deep[b])
break;
if(deep[b]-deep[a]<(1<<i))
i--;
else
b=pa[b][i];
}
for(i=0; (1<<i)<deep[b]; i++)
;
i--;
for(;;) {
if(a==b)
return a;
if(pa[a][0]==pa[b][0])
return pa[a][0];
if(pa[a][i]==pa[b][i])
i--;
else
a=pa[a][i],b=pa[b][i];
}
}
LL Query(int a,int top,LL val){
// Max one not equiv val
LL res=-inf;
per(i,20,0){
if(pa[a][i]&&deep[pa[a][i]]>=deep[top]){
// judge if pa[a][i] exists
if(mx[a][i]==val)res=max(res,mxx[a][i]);
else res=max(res,mx[a][i]);
a=pa[a][i];
}
}
return res;
}
/*_________________________________________________________lca*/
int fa[maxn];
int fin(int a) {
return fa[a]==a?a:fa[a]=fin(fa[a]);
}
struct node {
int a,b;LL v;
bool operator<(const node&R)const {
return v<R.v;
}
} e[maxn*3];
/*_________________________________________________________MST*/
bool vis[maxn*3];
int main() {
int n=rd(),m=rd();
rep(i,1,n)
fa[i]=i;
rep(i,1,m)
scanf("%d%d%lld",&e[i].a,&e[i].b,&e[i].v);
sort(e+1,e+1+m);
LL now=0;
rep(i,1,m) {
int f1=fin(e[i].a), f2=fin(e[i].b);
if(f1==f2)
continue;
vis[i]=1;
add(e[i].a,e[i].b,e[i].v),
add(e[i].b,e[i].a,e[i].v);
fa[f1]=f2;
now+=e[i].v;
}
dfs(1,0,0);
init(n);
LL ans=inf;
rep(i,1,m) {
if(vis[i])
continue;
int a=e[i].a, b=e[i].b; LL v=e[i].v;
int L=lca(a,b);
LL sub=max(Query(a,L,v),Query(b,L,v));
if(sub<0)continue;
ans=min(ans,now-sub+v);
}
printf("%lld\n",ans);
return 0;
}