[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 存在多组数 ...
随机推荐
- 团队作业4Alpha冲刺
仓库地址:https://gitee.com/ILoveFunGame/game_strategy_network.git 第一天 2018/6/13 1.1 今日完成任务情况以及遇到的问题. 1.1 ...
- go_函数
函数语法要点 返回值类型写在最后面 可返回多个值 函数可作为参数 没有默认参数,可选参数,只有可变参数列表(...int) package main import ( "fmt" ...
- NPC问题及其解决方法(回溯法、动态规划、贪心法、深度优先遍历)
NP问题(Non-deterministic Polynomial ):多项式复杂程度的非确定性问题,这些问题无法根据公式直接地计算出来.比如,找大质数的问题(有没有一个公式,你一套公式,就可以一步步 ...
- 快速上手Runtime(二)之给分类添加属性
我们都知道,分类是不能直接添加属性的,那么我们有时候又需要实现这个功能,那么我们应该怎么办才能为分类添加上属性呢. Runtime给分类添加属性原理 给一个类声明属性,其实本质就是给这个类添加关联,并 ...
- winfrom保存图片,将文件夹中图片放入listview,与撤回操作
之前那些操作完成对图片的修改之后,就是要保存图片了. 这里保存用到一个SaveFileDialog控件,可以获取用户选择的保存文件的路径. ) { SaveFileDialog saveImageDi ...
- Mongodb基于oplog恢复至任意时间
背景: 最近后端基于mongo的项目越来越多,MySQL基于冷备份+binlog可以恢复至任意时间点,那么mongo是否有同样的功能呢?经过调研发现可以通过dump+oplog可以实现粒度更细致的恢复 ...
- 搭建自己的MQTT服务器
搭建自己的MQTT服务器 物联网电子世界 百家号08-2903:04 MQTT协议是广泛应用的物联网协议,使用测试MQTT协议需要MQTT的代理.有两种方法使用MQTT服务,一是租用现成的MQTT服务 ...
- Webstorm 10.0.4 配置
1. 更换为sublime text的keymaps: https://github.com/ekaragodin/idea-sublime-keymap (idea-sublime-keymap- ...
- C语言访问mysql数据库
mysql中新建的数据库为hyx,hyx中的表为my_schema,表中的数据为下图: 编写代码,访问表中的数据,测试代码如下: #include "stdafx.h" #incl ...
- MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error
今天购物车突然不能添加了,发现redis报错了,重启了一下好了,一会又报错了. 错误信息: MISCONF Redis is configured to save RDB snapshots, but ...