BZOJ 1977 次小生成树(最近公共祖先)
2016-05-27 20:44
363 查看
题意:求一棵树的严格次小生成树,即权值严格大于最小生成树且权值最小的生成树。
先求最小生成树,对于每个不在树中的边,取两点间路径的信息,如果这条边的权值等于路径中的权值最大值,那就删掉路径中的次大值,加上这条非树边,更新答案;否则删掉路径中的最大值,加上这条非树边,更新答案。
先求最小生成树,对于每个不在树中的边,取两点间路径的信息,如果这条边的权值等于路径中的权值最大值,那就删掉路径中的次大值,加上这条非树边,更新答案;否则删掉路径中的最大值,加上这条非树边,更新答案。
#include<algorithm> #include<cstdio> #include<cmath> #include<cstring> #include<iostream> #define ll long long struct edge{ int u,v,id; ll w; }e[300005]; int tot,go[600005],first[300005],next[600005]; ll val[600005]; int fa[100005][18],deep[100005],F[100005],bin[105],n,m; ll mx1[100005][18],mx2[100005][18],ans1,ans2; int read(){ char ch=getchar();int t=0,f=1; while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } ll Read(){ char ch=getchar();ll t=0,f=1; while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } bool cmp(edge a,edge b){ return a.w<b.w; } void insert(int x,int y,ll z){ tot++; go[tot]=y; next[tot]=first[x]; first[x]=tot; val[tot]=z; } void add(int x,int y,int z){ insert(x,y,z);insert(y,x,z); } int find(int x){ if (F[x]==x) return x; else return (find(F[x])); } void up(ll x,ll &y){ if (x>y) y=x; } void work(int x,int i){ mx1[x][i]=std::max(mx1[fa[x][i-1]][i-1],mx1[x][i-1]); if (mx1[fa[x][i-1]][i-1]<mx1[x][i]) up(mx1[fa[x][i-1]][i-1],mx2[x][i]); if (mx1[x][i-1]<mx1[x][i]) up(mx1[x][i-1],mx2[x][i]); up(mx2[x][i-1],mx2[x][i]); up(mx2[fa[x][i-1]][i-1],mx2[x][i]); } void dfs(int x,int f){ for (int i=1;i<=17;i++) fa[x][i]=fa[fa[x][i-1]][i-1],work(x,i); for (int i=first[x];i;i=next[i]){ int pur=go[i]; if (pur==f) continue; deep[pur]=deep[x]+1; fa[pur][0]=x; mx1[pur][0]=val[i]; mx2[pur][0]=0; dfs(pur,x); } } void up(ll x,ll &a,ll &b){ if (x>a) b=a,a=x; else if (x>b&&x<a) b=x; } void lca(int x,int y){ ans1=0,ans2=0; if (deep[x]<deep[y]) std::swap(x,y); int t=deep[x]-deep[y]; for (int i=0;i<=17;i++) if (t&bin[i]) { up(mx1[x][i],ans1,ans2); up(mx2[x][i],ans1,ans2); x=fa[x][i]; } for (int i=17;i>=0;i--) if (fa[x][i]!=fa[y][i]) { up(mx1[x][i],ans1,ans2); up(mx2[x][i],ans1,ans2); up(mx1[y][i],ans1,ans2); up(mx2[y][i],ans1,ans2); x=fa[x][i]; y=fa[y][i]; } if (x!=y){ up(mx1[x][0],ans1,ans2); up(mx2[x][0],ans1,ans2); up(mx1[y][0],ans1,ans2); up(mx2[y][0],ans1,ans2); } } int main(){ bin[0]=1; for (int i=1;i<=17;i++) bin[i]=bin[i-1]*2; n=read();m=read(); for (int i=1;i<=m;i++){ e[i].u=read(); e[i].v=read(); e[i].w=Read(); e[i].id=0; } for (int i=1;i<=n;i++) for (int j=0;j<=17;j++) mx1[i][j]=mx2[i][j]=0; std::sort(e+1,e+1+m,cmp); ll sum=0; for (int i=1;i<=n;i++) F[i]=i; for (int i=1;i<=m;i++) if (find(e[i].u)!=find(e[i].v)){ F[find(e[i].u)]=find(e[i].v); e[i].id=1; add(e[i].u,e[i].v,e[i].w); sum+=e[i].w; } dfs(1,0); ll Ans=10000000000000000LL; for (int i=1;i<=m;i++) if (!e[i].id){ lca(e[i].u,e[i].v); if (e[i].w==ans1) Ans=std::min(Ans,sum-ans2+e[i].w); else Ans=std::min(Ans,sum-ans1+e[i].w); } printf("%lld\n",Ans); }
相关文章推荐
- 拼装网页路径
- 动态规划1003
- scala Manifest、ClassTag、TypeTag的学习
- UIView动画实现
- Android基于特征码查杀手机病毒
- vim用法
- python中单,双引号和三个双引号的区别
- 73条日常Linux shell命令汇总
- hdu 2544 最短路
- RestTemplate使用总结
- Android 自定义View (一)
- AndroidStudio的用法详解
- Google推荐的图片加载库Glide介绍
- /proc/sys/net/ipv4/ip_forward
- 大道至简阅读笔记03
- HandNet 数据集
- bash 提示
- leakCanary 在eclipse使用
- handler使用3
- BLE 总结