题目大意:给定一个无向图,求严格次小生成树
这题纠结了我同学很久。。。首先如果是不严格的次小生成树(权值可以等于最小生成树),那么我们就有一个很简单明了的算法:
首先求出最小生成树 然后建立倍增LCA 枚举没进入最小生成树的边 在边的两端点的路径上寻找最大的边权 用最小生成树权值-最大边权+新边权去更新ans即可
但是这道题是严格次小生成树 那么也好办 我们记录一个次大边权 如果枚举到的边权和最大边权相等 就用路径上的次大边权代替最大边权去更新即可
于是我们只需要在倍增的时候记录最大权值和次大权值即可 注意建立倍增LCA的时候次大值的讨论 这里容易出问题
假期被罚十道题第一道。。。苦逼的娃,同学们都刷了四道了0.0 10%达成
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 using namespace std; typedef long long ll; struct edge{ int x,y,f; bool used; bool operator < (const edge &y) const { return f < y.f; } }edges[300300]; struct abcd{ int to,f,next; }table[M<<1]; int head[M],tot; int n,m,fa[M][20],f_max[M][20],f_2th_max[M][20],dpt[M]; ll ans_min,ans_2th_min=~0ull>>1; int belong[M]; int find(int x) { if(!belong[x]||belong[x]==x) return belong[x]=x; return belong[x]=find(belong[x]); } void add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } void dfs(int x) { int i; dpt[x]=dpt[fa[x][0]]+1; for(i=head[x];i;i=table[i].next) { if(table[i].to==fa[x][0]) continue; fa[table[i].to][0]=x; f_max[table[i].to][0]=table[i].f; dfs(table[i].to); } } int Find_F_Max(int x,int y) { int j,re=0; if(dpt[x]<dpt[y]) swap(x,y); for(j=19;~j;j--) if(dpt[fa[x][j]]>=dpt[y]) re=max(re,f_max[x][j]),x=fa[x][j]; if(x==y) return re; for(j=19;~j;j--) if(fa[x][j]!=fa[y][j]) { re=max(re,f_max[x][j]); re=max(re,f_max[y][j]); x=fa[x][j]; y=fa[y][j]; } re=max(re,f_max[x][0]); re=max(re,f_max[y][0]); return re; } int Find_F_2th_Max(int x,int y,int z) { int j,re=0; if(dpt[x]<dpt[y]) swap(x,y); for(j=19;~j;j--) if(dpt[fa[x][j]]>=dpt[y]) { if(f_max[x][j]!=z) re=max(re,f_max[x][j]); else re=max(re,f_2th_max[x][j]); x=fa[x][j]; } if(x==y) return re; for(j=19;~j;j--) if(fa[x][j]!=fa[y][j]) { if(f_max[x][j]!=z) re=max(re,f_max[x][j]); else re=max(re,f_2th_max[x][j]); if(f_max[y][j]!=z) re=max(re,f_max[y][j]); else re=max(re,f_2th_max[y][j]); x=fa[x][j]; y=fa[y][j]; } j=0; if(f_max[x][j]!=z) re=max(re,f_max[x][j]); else re=max(re,f_2th_max[x][j]); if(f_max[y][j]!=z) re=max(re,f_max[y][j]); else re=max(re,f_2th_max[y][j]); return re; } int main() { int i,j; cin>>n>>m; for(i=1;i<=m;i++) scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f); sort(edges+1,edges+m+1); for(i=1;i<=m;i++) { int fx=find(edges[i].x),fy=find(edges[i].y); if(fx!=fy) { edges[i].used=true; belong[fx]=fy; ans_min+=edges[i].f; add(edges[i].x,edges[i].y,edges[i].f); add(edges[i].y,edges[i].x,edges[i].f); } } dfs(1); for(j=1;j<=19;j++) for(i=1;i<=n;i++) { int f=fa[i][j-1]; fa[i][j]=fa[f][j-1]; if( f_max[i][j-1] > f_max[f][j-1] ) { f_max[i][j]=f_max[i][j-1]; f_2th_max[i][j]=max( f_2th_max[i][j-1] , f_max[f][j-1] ); } else { f_max[i][j]=f_max[f][j-1]; if( f_max[i][j-1] < f_max[f][j-1] ) f_2th_max[i][j]=max( f_2th_max[f][j-1] , f_max[i][j-1] ); else f_2th_max[i][j]=max( f_2th_max[i][j-1] , f_2th_max[f][j-1] ); } f_max[i][j]=max( f_max[i][j-1] , f_max[f][j-1] ); } for(i=1;i<=m;i++) if(!edges[i].used) { int temp=Find_F_Max(edges[i].x,edges[i].y); if(temp==edges[i].f) temp=Find_F_2th_Max(edges[i].x,edges[i].y,temp); ans_2th_min=min(ans_2th_min,ans_min-temp+edges[i].f); } cout<<ans_2th_min<<endl; }