#include<bits/stdc++.h>
#define re return
#define MAX(a,b) (a)>(b)?(a):(b)
#define inc(i,l,r) for(int i=l;i<=r;++i)
const int maxn=100000+5,maxm=300005;
template<typename T>inline void read(T&x)
{
char c;bool f=0;
while((c=getchar())<'0'||c>'9') if(c=='-')f=1;
x=c^48;
while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
if(f)x=-x;
}
using namespace std;
int n,m,k1,k,head[maxn],f[maxn],vis[maxm],dep[maxn],fa[maxn][25],maxx[maxn][25],maxi[maxn][25];
long long ANS,ans=99999999999999999;//ans要赋ll最大值
struct node
{
int fr,to,val,nt;
bool operator<(node a)const{re val<=a.val;}
//自定义排序
}e[maxn<<1],e1[maxm];
inline void add1()
{
int x,y,z;read(x),read(y),read(z);
e1[++k1].to=y;e1[k1].fr=x;e1[k1].val=z;
}
inline void add(int x,int y,int z)
{
e[++k].to=y;e[k].val=z;e[k].nt=head[x];head[x]=k;
e[++k].to=x;e[k].val=z;e[k].nt=head[y];head[y]=k;
}
int find(int x)
{
re f[x]==x?x:f[x]=find(f[x]);
}
void kruskal()
{
//找出最小生成树
inc(i,1,n)f[i]=i;
sort(e1+1,e1+m+1);
int cnt=0;
for(int i=0;i<=k1;i++)
{
int v=find(f[e1[i].to]),u=find(f[e1[i].fr]);
if(v!=u)
{
vis[i]=1;
f[v]=u;
add(e1[i].to,e1[i].fr,e1[i].val);
ANS+=e1[i].val;
if(++cnt==n-1)
re;
}
}
}
void dfs(int u)
{
dep[u]=dep[fa[u][0]]+1;
倍增
for(int i=0;fa[fa[u][i]][i];i++)
{
fa[u][i+1]=fa[fa[u][i]][i]; //常规最近公共祖先
maxx[u][i+1]=MAX(maxx[fa[u][i]][i],maxx[u][i]);
//i到fa[[u][i+1]]最大路径
maxi[u][i+1]=MAX(maxi[fa[u][i]][i],maxi[u][i]);
//i到fa[[u][i+1]]严格次小路径
if(maxx[u][i+1]>maxx[fa[u][i]][i])
maxi[u][i+1]=MAX(maxi[u][i+1],maxx[fa[u][i]][i]);
else if(maxx[u][i+1]<maxx[fa[u][i]][i])
maxi[u][i+1]=MAX(maxi[u][i+1],maxx[u][i]);
找出绝对的次小路径
}
for(int i=head[u];i;i=e[i].nt)
{
int v=e[i].to;
if(v!=fa[u][0])
{
fa[v][0]=u;
maxx[v][0]=e[i].val;
maxi[v][0]=0xcfcfcfcf;
//赋初值
dfs(v);
}
}
}
int LCA(int u,int v,int cc)
{
int vv=0xcfcfcfcf;
if(dep[u]<dep[v])u^=v^=u^=v;
for(int i=20;i>=0;i--)
if(dep[fa[u][i]]>=dep[v])
{
if(maxx[u][i]!=cc)vv=MAX(vv,maxx[u][i]);
else vv=MAX(vv,maxi[u][i]);
如果最大值与当前要替换的路径相等,就选择次小路径
保证 所得生成树大于最小生成树
u=fa[u][i];
}
if(u==v)re vv;
for(int i=20;i>=0;i--)
if(fa[u][i]&&fa[u][i]!=fa[v][i])
{
if(maxx[u][i]!=cc)vv=MAX(vv,maxx[u][i]);
else vv=MAX(vv,maxi[u][i]);
u=fa[u][i];
if(maxx[v][i]!=cc)vv=MAX(vv,maxx[v][i]);
else vv=MAX(vv,maxi[v][i]);
v=fa[v][i];
}
if(maxx[u][0]!=cc)vv=MAX(vv,maxx[u][0]);
else vv=MAX(vv,maxi[u][0]);
if(maxx[v][0]!=cc)vv=MAX(vv,maxx[v][0]);
else vv=MAX(vv,maxi[v][0]);
re vv;
}
int main()
{
read(n),read(m);
inc(i,1,m)add1();
kruskal();
dfs(1);
for(int i=1;i<=k1;i++)
if(!vis[i])
{
long long sum=ANS;
sum-=LCA(e1[i].to,e1[i].fr,e1[i].val);
ans=min(ans,sum+e1[i].val);
}
printf("%lld",ans);
re 0;
}
严格次小生成树[BJWC2010]
最新推荐文章于 2024-01-10 09:28:46 发布