1. 程式人生 > >[模板] 嚴格次小生成樹

[模板] 嚴格次小生成樹

路徑 pro name () etc 一個 iostream 嚴格 生成

題目鏈接

先求當前圖中的最小生成樹,再將沒有選的邊一一安放(放完一個就卸下),這樣每次就形成一個環,再求這個環除了它以外的最短權值,這樣就會想到lca,因為樹的路徑是唯一的,並且時間也不會超時,再將原答案加上這條邊的權值減去最大的環上權值的最小值即為答案

調了一下午,哎~,板子打WA了,一個1<<i被我寫成了i<<1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace
std; inline long long read() { long long f=1,ans=0;char c; while(c<0||c>9){if(c==-)f=-1;c=getchar();} while(c>=0&&c<=9){ans=ans*10+c-0;c=getchar();} return ans*f; } long long n,m,f[100001]; struct node1{ long long u,v,w; }x[600001]; bool cmp(node1 x1,node1 x2) {
return x1.w<x2.w; } long long find(long long x) { if(f[x]==x) return x; return f[x]=find(f[x]); } struct node{ long long u,v,w; }xx[600001]; struct node3{ long long u,v,w,nex; }s[600001]; long long cntt; long long cnt; long long ans; long long head[100001]; long long maxn1[100001][18],maxn2[100001][18
],fa[100001][18],deep[100001]; long long data=0x3f3f3f3f3f3f3f3f; void add(long long u,long long v,long long w) { s[cntt].u=u,s[cntt].v=v,s[cntt].w=w,s[cntt].nex=head[u],head[u]=cntt++; } void dfs(long long f,long long fath) { deep[f]=deep[fath]+1; fa[f][0]=fath; for(long long i=1;(1<<i)<=deep[f];i++) { fa[f][i]=fa[fa[f][i-1]][i-1]; maxn1[f][i]=max(maxn1[f][i-1],maxn1[fa[f][i-1]][i-1]); if(maxn1[f][i-1]==maxn1[fa[f][i-1]][i-1]) maxn2[f][i]=max(maxn2[f][i-1],maxn2[fa[f][i-1]][i-1]); else maxn2[f][i]=max(min(maxn1[f][i-1],maxn1[fa[f][i-1]][i-1]),max(maxn2[f][i-1],maxn2[fa[f][i-1]][i-1])); } for(long long i=head[f];i!=-1;i=s[i].nex) { if(s[i].v==fath) continue; maxn1[s[i].v][0]=s[i].w; dfs(s[i].v,f); } } void kcal() { memset(head,-1,sizeof(head)); n=read(),m=read(); for(long long i=1;i<=n;i++) f[i]=i; for(long long i=1;i<=m;i++) x[i].u=read(),x[i].v=read(),x[i].w=read(); sort(x+1,x+m+1,cmp); for(long long i=1;i<=m;i++) { long long t1=find(x[i].u),t2=find(x[i].v); if(t1!=t2) { f[t2]=t1; ans+=x[i].w; add(x[i].u,x[i].v,x[i].w),add(x[i].v,x[i].u,x[i].w); } else xx[++cnt].u=x[i].u,xx[cnt].v=x[i].v,xx[cnt].w=x[i].w; } } long long lca(long long u,long long v,long long w) { long long dis1=-1,dis2=-1; if(deep[u]<deep[v]) swap(u,v); for(long long i=17;i>=0;i--) { if(deep[u]-(1<<i)>=deep[v]) { dis2=max(dis2,maxn2[u][i]); if(maxn1[u][i]>dis1) dis2=max(dis1,max(dis2,maxn2[u][i])),dis1=maxn1[u][i]; else dis2=max(dis2,maxn1[u][i]); u=fa[u][i]; } } if(u==v) { if(dis1==w) return dis2; return dis1; } for(long long i=17;i>=0;i--) { if(fa[u][i]==fa[v][i]) continue; dis2=max(dis2,maxn2[u][i]); if(maxn1[u][i]>dis1) dis2=max(dis1,max(dis2,maxn2[u][i])),dis1=maxn1[u][i]; else dis2=max(dis2,maxn1[u][i]); u=fa[u][i]; dis2=max(dis2,maxn2[v][i]); if(maxn1[v][i]>dis1) dis2=max(dis1,max(dis2,maxn2[v][i])),dis1=maxn1[v][i]; else dis2=max(dis2,maxn1[v][i]); v=fa[v][i]; } dis2=max(dis2,maxn2[u][0]); if(maxn1[u][0]>dis1) dis2=max(dis1,max(dis2,maxn2[u][0])),dis1=maxn1[u][0]; else dis2=max(dis2,maxn1[u][0]); u=fa[u][0]; dis2=max(dis2,maxn2[v][0]); if(maxn1[v][0]>dis1) dis2=max(dis1,max(dis2,maxn2[v][0])),dis1=maxn1[v][0]; else dis2=max(dis2,maxn1[v][0]); v=fa[v][0]; if(dis1==w) return dis2; return dis1; } int main() { kcal(); dfs(1,0); for(long long i=1;i<=cnt;i++) data=min(data,ans+xx[i].w-lca(xx[i].u,xx[i].v,xx[i].w)); if(ans!=data)cout<<data; else cout<<data+1; }

[模板] 嚴格次小生成樹