给定一张无向图,求严格次小的生成树(保证存在)
非严格次小的很好做
kruskal求出最小生成树,倍增求LCA与区间最大边权
枚举剩下的边两端点之间的最大值比较即可.
但是要严格次小的话,要在倍增时维护一个次大边权值
枚举时如果当前边与最大相等则比较次大
做的时候一堆奇怪的bug。。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=100004,M=300005;
struct Edge{
int u,v,nex,flag;LL w;
}e[M*2],edge[M*2];
int n,m,tot,head[N],fa[N][20],dep[N],pa[N];
LL ma[N][20],m2[N][20],sum;
inline void Addedge(int u,int v,LL w)
{
edge[++tot].v=v;edge[tot].nex=head[u];edge[tot].w=w;head[u]=tot;
}
bool cmp(const Edge &a,const Edge &b)
{
return a.w<b.w;
}
int find(int v)
{
if(pa[v]==v)return v;
return pa[v]=find(pa[v]);
}
void kruskal()
{
int cnt=0;
sort(e+1,e+m+1,cmp);
for(int i=1;i<=n;i++)pa[i]=i;
for(int i=1;i<=m;i++)
{
if(cnt==n-1)break;
int x=find(e[i].u),y=find(e[i].v);
if(x!=y){
pa[x]=y;sum+=e[i].w;cnt++;
Addedge(e[i].u,e[i].v,e[i].w);
Addedge(e[i].v,e[i].u,e[i].w);
e[i].flag=1;
//e[i].nex=head[e[i].u];head[e[i].u]=i;
}
}
}
void dfs(int u,int f)
{
for(int i=1;i<=19;i++){
int ff=fa[u][i-1];
fa[u][i]=fa[ff][i-1];
ma[u][i]=max(ma[u][i-1],ma[ff][i-1]);
//m2[u][i]=getsec(ma[u][i-1],m2[u][i-1],ma[ff][i-1],m2[ff][i-1]);
m2[u][i]=max(m2[u][i-1],m2[ff][i-1]);
if(ma[u][i-1]!=ma[ff][i-1])
m2[u][i]=max(m2[u][i],min(ma[u][i-1],ma[ff][i-1]));
}
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v,w=edge[i].w;
if(v==f)continue;
fa[v][0]=u;ma[v][0]=w;dep[v]=dep[u]+1;
dfs(v,u);
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=19;i>=0;i--)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y)return x;
for(int i=19;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
LL ans=(1LL<<40);
void cal(int x,int lca,LL v)
{
LL c1=0,c2=0;
int h=dep[x]-dep[lca];
for(int i=19;i>=0;i--)if(h&(1<<i))
{
if(ma[x][i]>c1)
c2=c1,c1=ma[x][i];
c2=max(c2,m2[x][i]);
h-=(1<<i);
}
if(v==c1)ans=min(ans,v-c2);
else ans=min(ans,v-c1);
}
void ask(int x,int y,LL len)
{
int lca=LCA(x,y);
cal(x,lca,len);cal(y,lca,len);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,u,v,w;i<=m;i++){
scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w);
}
kruskal();
dfs(1,0);
for(int i=1;i<=m;i++)
{
if(e[i].flag)continue;
ask(e[i].u,e[i].v,e[i].w);
}
printf("%lld\n",sum+ans);
return 0;
}