[BJOI2010] 严格次小生成树
题目链接
一个严格次小生成树的模板题。
看到次小生成树,我们有一个很直观的想法就是先构造出来最小生成树,然后将这个最小生成树上面最大的一条边替换成和它值最相近而且比他大的边。
那么首先就是用kruskal算法算出来最小生成树,我们称在这个最小生成树上面的边为树边(打上标记),不在的边为非树边。
之后就是用非树边替换树边了。
考虑怎么替换。我们可以通过枚举每一条非树边,然后找到这条边对应的两端节点在最小生成树上的最大边权,然后替换。
正确性显然,因为非树边肯定比树边劣,而当我们替换了树边之后,肯定是次小的。
但是要注意一点就是这个题是严格次小的,所以我们在记录最大值的时候还要记录次大值。
然后就是如何找最小生成树上两个点之间的边权最大值和次大值。观察数据范围,3e5的数据显然不能一个一个暴力,那么就是倍增或者树剖优化了。
在这里给出倍增的做法,代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 300010
using namespace std;
int n,m,t;
long long res=(long long)1e15,sum;
int head[MAXN],dis[MAXN],fa[MAXN],g[MAXN][32],done[MAXN],dep[MAXN],maxx1[MAXN][32],maxx2[MAXN][32];
struct Edge{int nxt,to,dis,from;}edge[MAXN<<1],pre[MAXN<<1];
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline bool cmp(struct Edge x,struct Edge y){return x.dis<y.dis;}
inline void add(int from,int to,int dis){edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,head[from]=t;}
inline void init()
{
for(int k=1;k<=21;k++)
for(int i=1;i<=n;i++)
{
g[i][k]=g[g[i][k-1]][k-1];
maxx1[i][k]=max(maxx1[g[i][k-1]][k-1],maxx1[i][k-1]);
if(maxx1[i][k-1]==maxx1[g[i][k-1]][k-1])
maxx2[i][k]=max(maxx2[i][k-1],maxx2[g[i][k-1]][k-1]);
else
{
maxx2[i][k]=min(g[i][k-1],maxx1[g[i][k-1]][k-1]);
maxx2[i][k]=max(maxx2[i][k],max(maxx2[i][k-1],maxx2[g[i][k-1]][k-1]));
}
}
}
inline void kruskal()
{
int cnt=0;
for(int i=1;i<=m;i++)
{
int a=find(pre[i].from),b=find(pre[i].to);
if(a!=b)
{
fa[a]=b,done[i]=1;
cnt++,sum+=pre[i].dis;
add(pre[i].from,pre[i].to,pre[i].dis);
add(pre[i].to,pre[i].from,pre[i].dis);
}
if(cnt==n-1) return;
}
}
inline void dfs(int now)
{
for(int i=head[now];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v!=g[now][0])
g[v][0]=now,maxx1[v][0]=edge[i].dis,dep[v]=dep[now]+1,dfs(v);
}
}
inline void calc(int x,int &m1,int &m2,int k)
{
if(maxx1[x][k]>m1) m2=m1,m1=maxx1[x][k];
else if(maxx1[x][k]<m1) m2=max(m2,maxx1[x][k]);
m2=max(m2,maxx2[x][k]);
}
inline void lca(int x,int y,int w)
{
int cur_max1=0,cur_max2=0;
if(dep[x]<dep[y]) swap(x,y);
for(int i=21;i>=0;i--)
if((dep[x]-dep[y])&(1<<i))
calc(x,cur_max1,cur_max2,i),x=g[x][i];
if(x==y) {res=min(res,1ll*(w==cur_max1?w-cur_max2:w-cur_max1)); return;}
for(int i=21;i>=0;i--)
if(g[x][i]!=g[y][i])
calc(x,cur_max1,cur_max2,i),calc(y,cur_max1,cur_max2,i),x=g[x][i],y=g[y][i];
calc(x,cur_max1,cur_max2,0),calc(y,cur_max1,cur_max2,0);
res=min(res,1ll*(w==cur_max1?w-cur_max2:w-cur_max1));
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&pre[i].from,&pre[i].to,&pre[i].dis);
for(int i=1;i<=n;i++) fa[i]=i;
sort(&pre[1],&pre[m+1],cmp);
kruskal();
dep[1]=1;
dfs(1);
init();
for(int i=1;i<=m;i++)
{
if(done[i]==1) continue;
lca(pre[i].from,pre[i].to,pre[i].dis);
}
printf("%lld\n",sum+res);
return 0;
}
[BJOI2010] 严格次小生成树的更多相关文章
- [BJOI2010]次小生成树
OJ题号: BZOJ1977.COGS2453 题目大意: 给你一个无向连通图,求严格次小生成树. 思路: 对于一般次小生成树,我们有一个结论:一般次小生成树一定可以通过替换掉最小生成树某一条边得到. ...
- HDU 4081Qin Shi Huang's National Road System(次小生成树)
题目大意: 有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点.秦始皇希望这所有n-1条路长度之和最短.然后徐福突然有冒出来,说是他有魔法,可以不用人力.财力就变 ...
- POJ1679 The Unique MST[次小生成树]
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28673 Accepted: 10239 ...
- The Unique MST(次小生成树)
Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22335 Accepted: 7922 Description Give ...
- URAL 1416 Confidential --最小生成树与次小生成树
题意:求一幅无向图的最小生成树与最小生成树,不存在输出-1 解法:用Kruskal求最小生成树,标记用过的边.求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就 ...
- POJ1679The Unique MST(次小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 25203 Accepted: 8995 D ...
- [kuangbin带你飞]专题八 生成树 - 次小生成树部分
百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么 ...
- URAL 1416 Confidential(次小生成树)
题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1416 Zaphod Beeblebrox — President of the Impe ...
- ACM题目————次小生成树
Description 最小生成树大家都已经很了解,次小生成树就是图中构成的树的权值和第二小的树,此值也可能等于最小生成树的权值和,你的任务就是设计一个算法计算图的最小生成树. Input 存在多组数 ...
随机推荐
- MyBatis 学习记录2 Mapper对象是如何生成的
主题 以前我一直有一个问题不懂.并且觉得很神奇.就是Mybatis我们开发的时候只需要定义接口,并没有写实现类,为什么我们运行的时候就可以直接使用? 现在我想分享下这部分大致是怎么实现的. 在启动的时 ...
- Spring 学习记录4 ResourceLoader
ResourceLoader Spring的ApplicationContext继承了ResourceLoader接口.这个接口主要就是可以加载各种resource.. 接口还是比较简单的: /* * ...
- 前面部分(WCF全面解析1)
WCF全面解析 [同力推荐] 我经历了COM时代,一直把Don BOx的<COM本质论>奉为我的指路明灯.能把SOA机理和WCF这种特定厂商实现的技术讲得如<COM本质论>一样 ...
- [KVM][guestfs] 安装 guestfs-python 出错
pip install http://download.libguestfs.org/python/guestfs-1.36.13.tar.gz 执行后出错: 然后百度.谷歌,都是说安装 gcc 或者 ...
- ssh框架,工具类调用service层方法
解决方法: @Component//声明为spring组件 public class CopyFileUtil{ @Autowired private DataFileManager dataFile ...
- linux ifconfig显示 command not found
本人装的是centos7 想看下网络配置 结果显示如图: 正常情况下 ifconfig 是在超级管理员 的所属的目录 sbin/下的命令 现在来查看该目录下. 没有找到,别急 用 yum sear ...
- c++ 备忘录模式(memento)
备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态[DP].举个简单的例子,我们玩游戏时都会保存进度,所保存的进度以文件的 ...
- 抓包工具Fidder移动端HTTP请求抓包详解
第一步:下载神器Fiddler,下载链接: http://fiddler2.com/get-fiddler 下载完成之后,傻瓜式的安装一下了! 第二步:设置Fiddler打开Fiddler, ...
- 面向对象的JavaScript-005-Function.prototype.call()的3种作用
1. // call的3种作用 // 1.Using call to chain constructors for an object function Product(name, price) { ...
- 王子和公主 UVa10635
[题目描述]:王子和公主 一个王子和公主在n*n的格子中行走,这些格子是有1....n^2的编号的.现在给定p+1个数,再给定q+1个数,公主和王子可以选择其中某些格子行走,求他们最多能走几个相同的格 ...