【BJOI2010】次小生成树-最小生成树+倍增LCA
来源:互联网 发布:矩阵行列式的计算 编辑:程序博客网 时间:2024/06/05 01:45
题目大意:给定一个带边权的无向图,求该图中严格次小生成树上的边权和。
做法:本题需要用到最小生成树+倍增LCA。
所谓严格次小生成树,就是边权和严格大于最小生成树的边权和最小的生成树。我们求非严格次小生成树时,是对于每一条不在最小生成树中的边,将它加入后,再从构成的环中去掉一个除了它之外最大的边,所有这样构成的树中边权和最小的就是次小生成树了。然而这次要求严格次小生成树,这就意味着它的边权和必须严格大于最小生成树,所以对于每条不在最小生成树中的边,如果它和它两个端点在最小生成树上路径中最大边相等,就要用严格次大的边来作为被删掉的边。树上两点间严格次大的边权可以用倍增LCA来找,具体的预处理方法这里解释不清,请看代码吧。这样一来,时间复杂度是
以下是本人代码:
#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>#define ll long longusing namespace std;int n,m;ll totalsum,ans=2000000000;int first[100010],tot=0,f[100010];int fa[100010][21]={0},mx[100010][21]={0},smx[100010][21]={0},dep[100010]={0};struct edge {int v,next;ll d;} e[200010];struct forsort {int x,y;ll z;} a[300010];bool chosen[300010]={0};bool cmp(forsort a,forsort b){ return a.z<b.z;}int find(int x){ int r=x,i=x,j; while(f[r]!=r) r=f[r]; while(i!=r) { j=f[i]; f[i]=r; i=j; } return r;}void merge(int a,int b){ int fa=find(a),fb=find(b); f[fa]=fb;}void insert(forsort a){ e[++tot].v=a.y,e[tot].d=a.z,e[tot].next=first[a.x],first[a.x]=tot; e[++tot].v=a.x,e[tot].d=a.z,e[tot].next=first[a.y],first[a.y]=tot;}void kruskal(){ sort(a+1,a+m+1,cmp); int now=0;totalsum=0; for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=m;i++) { if (now==n-1) break; int fx=find(a[i].x),fy=find(a[i].y); if (fx!=fy) { now++; totalsum+=a[i].z; chosen[i]=1; insert(a[i]); merge(a[i].x,a[i].y); } }}void dfs(int v){ smx[v][0]=-1; for(int i=first[v];i;i=e[i].next) if (e[i].v!=fa[v][0]) { fa[e[i].v][0]=v; mx[e[i].v][0]=e[i].d; dep[e[i].v]=dep[v]+1; dfs(e[i].v); }}void calc(ll &val1,ll val2,ll &val3,ll val4){ ll v1,v2; v1=max(val1,val2); if (val3>=val2) v2=val3; else if (val4>=val1) v2=val4; else if (val1!=val2) v2=min(val1,val2); else v2=max(val3,val4); val1=v1,val3=v2;}ll query(ll d,int x,int y){ ll mxx=0,smxx=0; if (dep[x]<dep[y]) swap(x,y); for(int i=20;i>=0;i--) if (dep[fa[x][i]]>=dep[y]) { calc(mxx,mx[x][i],smxx,smx[x][i]); x=fa[x][i]; } if (x!=y) { for(int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) { calc(mxx,mx[x][i],smxx,smx[x][i]); calc(mxx,mx[y][i],smxx,smx[y][i]); x=fa[x][i],y=fa[y][i]; } calc(mxx,mx[x][0],smxx,smx[x][0]); calc(mxx,mx[y][0],smxx,smx[y][0]); } if (d==mxx&&smxx!=-1) return smxx; else return mxx;}void work(){ dfs(1); for(int i=1;i<=20;i++) for(int j=1;j<=n;j++) { fa[j][i]=fa[fa[j][i-1]][i-1]; ll val1=mx[j][i-1],val2=mx[fa[j][i-1]][i-1],val3=smx[j][i-1],val4=smx[fa[j][i-1]][i-1]; mx[j][i]=max(val1,val2); if (val3>=val2) smx[j][i]=val3; else if (val4>=val1) smx[j][i]=val4; else if (val1!=val2) smx[j][i]=min(val1,val2); else smx[j][i]=max(val3,val4); } for(int i=1;i<=m;i++) if (!chosen[i]) { ll val=query(a[i].z,a[i].x,a[i].y); if (val!=-1) ans=min(ans,a[i].z-val); }}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%lld",&a[i].x,&a[i].y,&a[i].z); kruskal(); work(); printf("%lld",totalsum+ans); return 0;}
阅读全文
0 0
- 【BJOI2010】次小生成树-最小生成树+倍增LCA
- 【BJOI2010】次小生成树
- 次小生成树 倍增 LCA
- BZOJ 1977 次小生成树 倍增LCA
- bzoj1977 严格的次小生成树(LCA倍增)
- bzoj1977 [BeiJing2010组队]次小生成树 Tree (lca+倍增)
- bzoj1977: [BeiJing2010]次小生成树 kruskal+倍增LCA
- bzoj1977 次小生成树【最小生成树+倍增】
- 【bzoj1977】【次小生成树】【树上倍增】
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree Kruskal+倍增LCA
- BZOJ-1977 次小生成树 Tree 树上倍增LCA+Kruskal+位运算
- BZOJ 1977 Tree 次小生成树 (kruskal st表 倍增lca)
- bzoj 1977: [BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
- 最大生成树+LCA倍增
- 【UVa】11354 Bond 最小生成树,动态LCA,倍增思想
- bzoj3732(同货车运输,倍增lca+最小生成树)
- NOIP2013 货车运输 [LCA] [RMQ] [最小生成树] [ST倍增]
- UVA 11354 Bond(最小生成树+LCA倍增)
- 自定义复杂bean注册到spring
- PostGres+postGis 初级使用
- IntelliJ IDEA 使用心得与常用快捷键
- 如何配置maven项目连接私服(nexus)
- 机器学习算法-逻辑回归(LR)
- 【BJOI2010】次小生成树-最小生成树+倍增LCA
- keepalived高可用lvs 和nginx等
- 《程序员代码面试指南》Python实现(个人读书笔记)
- 改变android系统下文件属性
- 1.子查询知识体系,单行子查询,多行子查询
- mysql默认安装目录说明
- 中继器、网桥、路由器和网关的功能及区别
- 编写SSH框架碰到的问题
- MySQL中列子查询与行子查询操作的学习教程