bzoj1977次小生成樹
阿新 • • 發佈:2019-01-23
一道複雜一點的倍增題,需要記錄路徑的最大值和第二大值。
注意,嚴格次小生成樹,等生成樹性質要明確
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; inline ll read() { ll ans,f=1;char ch; while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0'; while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0'; return ans*f; } int n,m,fa[120005]; struct aa { int u,v; ll dis; bool o; bool operator <(const aa &b)const { return dis<b.dis; } }bian[320005]; int find(int i) { return fa[i]==i?i:fa[i]=find(fa[i]);} int head[120005],tot; struct aaa { int to,pre; ll dis; }edge[230005]; void addedge(int u,int v,ll dis) { edge[++tot].to=v;edge[tot].pre=head[u];edge[tot].dis=dis;head[u]=tot; } int f[120005][20],dep[120005];ll g1[120005][20],g2[120005][20]; ll se(ll a,ll b,ll c,ll d) { int j;ll t[4]={a,b,c,d}; sort(t,t+4); for (j=3;j>=0;j--) if (t[j]!=t[3]) break; if (j==-1) return 0; return t[j]; } void dfs(int u,int depth) { dep[u]=depth; for (int i=1;i<=18;i++) { int ff=f[u][i-1]; f[u][i]=f[ff][i-1]; g1[u][i]=max(g1[u][i-1],g1[ff][i-1]); g2[u][i]=se(g1[u][i-1],g1[ff][i-1],g2[u][i-1],g2[ff][i-1]); } for (int i=head[u];i;i=edge[i].pre) if (dep[edge[i].to]==0) { int v=edge[i].to; f[v][0]=u,g1[v][0]=edge[i].dis,g2[v][0]=0; dfs(v,depth+1); } } void updata(ll &fi,ll &se,ll a) { if (a>fi) se=fi,fi=a; else if (a==fi) return; else if (a>se) se=a; } void up(int &u,ll &fi,ll &se,int step) { for (int i=0;i<=18;i++) if (step&(1<<i)) { updata(fi,se,g1[u][i]);updata(fi,se,g2[u][i]); u=f[u][i]; } } ll lca(int u,int v,ll dis) { ll se=0,fi=0; if (dep[u]>dep[v]) up(u,fi,se,dep[u]-dep[v]); else up(v,fi,se,dep[v]-dep[u]); for (int i=18;i>=0;i--) if (f[u][i]!=f[v][i]) { updata(fi,se,g1[u][i]);updata(fi,se,g1[v][i]); updata(fi,se,g2[u][i]);updata(fi,se,g2[v][i]); u=f[u][i],v=f[v][i]; } if (u!=v) updata(fi,se,g1[u][0]),updata(fi,se,g1[v][0]); if (dis>fi) return fi;else return se; } int main() { n=read(),m=read(); int x,y;ll z; for (int i=1;i<=m;i++) bian[i].u=read(),bian[i].v=read(),bian[i].dis=read(); sort(bian+1,bian+m+1); for (int i=1;i<=n;i++) fa[i]=i; ll sum=0,ans=1e16; for (int i=1;i<=m;i++) { int fu=find(bian[i].u),fv=find(bian[i].v); if (fu!=fv) { fa[fu]=fv; sum+=bian[i].dis; bian[i].o=true; addedge(bian[i].u,bian[i].v,bian[i].dis); addedge(bian[i].v,bian[i].u,bian[i].dis); } } dfs(1,1); for (int i=1;i<=m;i++) if (!bian[i].o) { ll mx=lca(bian[i].u,bian[i].v,bian[i].dis); if (mx!=0) ans=min(sum-mx+bian[i].dis,ans); } printf("%lld",ans); return 0; }