题目链接

一个严格次小生成树的模板题。

看到次小生成树,我们有一个很直观的想法就是先构造出来最小生成树,然后将这个最小生成树上面最大的一条边替换成和它值最相近而且比他大的边。

那么首先就是用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] 严格次小生成树的更多相关文章

  1. [BJOI2010]次小生成树

    OJ题号: BZOJ1977.COGS2453 题目大意: 给你一个无向连通图,求严格次小生成树. 思路: 对于一般次小生成树,我们有一个结论:一般次小生成树一定可以通过替换掉最小生成树某一条边得到. ...

  2. HDU 4081Qin Shi Huang's National Road System(次小生成树)

    题目大意: 有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点.秦始皇希望这所有n-1条路长度之和最短.然后徐福突然有冒出来,说是他有魔法,可以不用人力.财力就变 ...

  3. POJ1679 The Unique MST[次小生成树]

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 28673   Accepted: 10239 ...

  4. The Unique MST(次小生成树)

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 22335   Accepted: 7922 Description Give ...

  5. URAL 1416 Confidential --最小生成树与次小生成树

    题意:求一幅无向图的最小生成树与最小生成树,不存在输出-1 解法:用Kruskal求最小生成树,标记用过的边.求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就 ...

  6. POJ1679The Unique MST(次小生成树)

    The Unique MST Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 25203   Accepted: 8995 D ...

  7. [kuangbin带你飞]专题八 生成树 - 次小生成树部分

    百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么 ...

  8. URAL 1416 Confidential(次小生成树)

    题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1416 Zaphod Beeblebrox — President of the Impe ...

  9. ACM题目————次小生成树

    Description 最小生成树大家都已经很了解,次小生成树就是图中构成的树的权值和第二小的树,此值也可能等于最小生成树的权值和,你的任务就是设计一个算法计算图的最小生成树. Input 存在多组数 ...

随机推荐

  1. Java中instanceof和isInstance的具体区别

    Java中instanceof和isInstance的具体区别 在Think in Java泛型这一章遇到这个问题,一些博客模糊提到了isInstance是instanceof的动态实现,查阅文档参考 ...

  2. 【304】python专题-读取xml文件

    参考:XML DOM 参考手册(w3school) 参考:python专题-读取xml文件 参考:请问用python怎么修改xml的节点值? 1. 读取标签内的文本(Python) 如下的 xml 文 ...

  3. Build/Run Instructions for Codec Engine Examples

    General Information This page explains how to build the examples provided in the Codec Engine (CE) p ...

  4. C 预处理小结

    预处理功能主要包括宏定义,文件包含,条件编译三部分.分别对应宏定义命令,文件包含命令,条件编译命令三部分实现. 预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换.预处理 ...

  5. Linux 下启动两个tomcat

    Linux 下启动两个tomcat 闲来无事学习nginx,想要配置个load balance.可是先决条件是:得有两个web容器.两个电脑是不用想了.只能想办法在一个机器上启动两个tomcat.原以 ...

  6. linux zip解压缩中文乱码

    这里提供两个解决方案: 1.python处理下:https://gist.github.com/wangjiezhe/7841a350983a147b6d7e 2.java的zip4j:http:// ...

  7. 10个最新手机美食APP界面设计欣赏

    移动软件时代,简单下载美食app,动动手指,滑动几下手机屏幕,即可足不出户,搜索,预定和购买各路美食.然而,对于作为手机app UI 界面设计师的你来说,最大的问题并不在于如何使用这些美食软件来方便生 ...

  8. centos踩坑指南之安装composer

    composer是php的一个依赖管理器,那么安装composer可以快速编译php 但是在centos7以上 安装composer的有一个步骤有个小问题 对于centos6来说是 sudo mv c ...

  9. Linux Mint 17使用配置

    => 调亮度: 方法一: 每次开机或注销登录之后需要重新设置 > /sys/class/backlight/intel_backlight/brightness #根据自己需要调值,如20 ...

  10. Android动态加载--JVM 类加载机制

    动态加载,本质上是通过JVM类加载机制将插件模块加载到宿主apk中,并通过android的相关运行机制,实现插件apk的运行.因此熟悉JVM类加载的机制非常重要. 类加载机制:虚拟机把描述类的数据从C ...