BZOJ 1977 次小生成树 倍增LCA

来源:互联网 发布:电气控制系统设计软件 编辑:程序博客网 时间:2024/05/22 13:52

题目大意:给定一个无向图,求严格次小生成树

这题纠结了我同学很久。。。首先如果是不严格的次小生成树(权值可以等于最小生成树),那么我们就有一个很简单明了的算法:

首先求出最小生成树 然后建立倍增LCA 枚举没进入最小生成树的边 在边的两端点的路径上寻找最大的边权 用最小生成树权值-最大边权+新边权去更新ans即可

但是这道题是严格次小生成树 那么也好办 我们记录一个次大边权 如果枚举到的边权和最大边权相等 就用路径上的次大边权代替最大边权去更新即可

于是我们只需要在倍增的时候记录最大权值和次大权值即可 注意建立倍增LCA的时候次大值的讨论 这里容易出问题

假期被罚十道题第一道。。。苦逼的娃,同学们都刷了四道了0.0 10%达成

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define M 100100using 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]);elsere=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]);elsere=max(re,f_2th_max[x][j]);if(f_max[y][j]!=z)re=max(re,f_max[y][j]);elsere=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]);elsere=max(re,f_2th_max[x][j]);if(f_max[y][j]!=z)re=max(re,f_max[y][j]);elsere=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] );elsef_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;}


0 0
原创粉丝点击