bzoj1977: [BeiJing2010]次小生成树 kruskal+倍增LCA

来源:互联网 发布:json数组转换java对象 编辑:程序博客网 时间:2024/06/06 20:24

给定一张无向图,求严格次小的生成树(保证存在)

非严格次小的很好做

kruskal求出最小生成树,倍增求LCA与区间最大边权

枚举剩下的边两端点之间的最大值比较即可.

但是要严格次小的话,要在倍增时维护一个次大边权值

枚举时如果当前边与最大相等则比较次大

做的时候一堆奇怪的bug。。

#include <bits/stdc++.h>#define LL long longusing namespace std;const int N=100004,M=300005;struct Edge{int u,v,nex,flag;LL w;}e[M*2],edge[M*2];int n,m,tot,head[N],fa[N][20],dep[N],pa[N];LL ma[N][20],m2[N][20],sum;inline void Addedge(int u,int v,LL w){edge[++tot].v=v;edge[tot].nex=head[u];edge[tot].w=w;head[u]=tot;}bool cmp(const Edge &a,const Edge &b){return a.w<b.w;}int find(int v){if(pa[v]==v)return v;return pa[v]=find(pa[v]);}void kruskal(){int cnt=0;sort(e+1,e+m+1,cmp);for(int i=1;i<=n;i++)pa[i]=i;for(int i=1;i<=m;i++){if(cnt==n-1)break;int x=find(e[i].u),y=find(e[i].v);if(x!=y){pa[x]=y;sum+=e[i].w;cnt++;Addedge(e[i].u,e[i].v,e[i].w);Addedge(e[i].v,e[i].u,e[i].w);e[i].flag=1;//e[i].nex=head[e[i].u];head[e[i].u]=i;}}}void dfs(int u,int f){for(int i=1;i<=19;i++){int ff=fa[u][i-1];fa[u][i]=fa[ff][i-1];ma[u][i]=max(ma[u][i-1],ma[ff][i-1]);//m2[u][i]=getsec(ma[u][i-1],m2[u][i-1],ma[ff][i-1],m2[ff][i-1]);m2[u][i]=max(m2[u][i-1],m2[ff][i-1]);if(ma[u][i-1]!=ma[ff][i-1])  m2[u][i]=max(m2[u][i],min(ma[u][i-1],ma[ff][i-1]));}for(int i=head[u];i;i=edge[i].nex){int v=edge[i].v,w=edge[i].w;if(v==f)continue;fa[v][0]=u;ma[v][0]=w;dep[v]=dep[u]+1;dfs(v,u);}}int LCA(int x,int y){if(dep[x]<dep[y])swap(x,y);for(int i=19;i>=0;i--)  if(dep[fa[x][i]]>=dep[y])    x=fa[x][i];if(x==y)return x;for(int i=19;i>=0;i--)  if(fa[x][i]!=fa[y][i])    x=fa[x][i],y=fa[y][i];return fa[x][0];}LL ans=(1LL<<40);void cal(int x,int lca,LL v){LL c1=0,c2=0;int h=dep[x]-dep[lca];for(int i=19;i>=0;i--)if(h&(1<<i)){if(ma[x][i]>c1)  c2=c1,c1=ma[x][i];c2=max(c2,m2[x][i]);h-=(1<<i);}if(v==c1)ans=min(ans,v-c2);else ans=min(ans,v-c1);}void ask(int x,int y,LL len){int lca=LCA(x,y);cal(x,lca,len);cal(y,lca,len);}int main(){scanf("%d%d",&n,&m);for(int i=1,u,v,w;i<=m;i++){scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w);}kruskal();dfs(1,0);for(int i=1;i<=m;i++){if(e[i].flag)continue;ask(e[i].u,e[i].v,e[i].w);}printf("%lld\n",sum+ans);return 0;}



阅读全文
0 0
原创粉丝点击