题目链接

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

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

那么首先就是用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. VRRP概述

    随着Internet的发展,人们对网络的可靠性的要求越来越高.对于局域网用户来说,能够时刻与外部网络保持联系是非常重要的. 通常情况下,内部网络中的所有主机都设置一条相同的缺省路由,指向出口网关(即图 ...

  2. [Python Study Notes]pynput实现对鼠标控制

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ...

  3. abseil的编译与使用

    项目中集成了abseil.abseil提供了cmake的编译,但是缺少make install命令. 于是有了下面的的一些命令,用于生成include和lib目录. function cmake_in ...

  4. 获取当前UnixTime的零点时间戳

    最近有个需求,开屏广告每天只出一次. 思路为如果出了开屏广告,则记录当前时间,下次来的时候,读取当前时间和上一次出开屏的时间. 算一下是不是在同一天即可. 我们的第一个想法是将上次开屏时间和当前时间归 ...

  5. [iOS]UIScrollView嵌套UITableView,超出屏幕的cell点击不了问题

    最初我是用UIScrollView嵌套了一个UIView,然后UIView里面嵌套UITableView,这样cell 就会超出屏幕那一部分点击不了. 解决方法如下,UITableView拖出来,作为 ...

  6. Elasticsearch from+size 超过10000结果解决方法

    方法一: 如果需要搜索分页,可以通过from size组合来进行.from表示从第几行开始,size表示查询多少条文档.from默认为0,size默认为10, 如果搜索size大于10000,需要设置 ...

  7. 146. LRU Cache (List, HashTable)

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

  8. 启动redis注意事项

    1.需要修改配置文件 redis.conf 三处 a.将bind 127.0.0.0    修改为  bind 0.0.0.0 b.daemonize no      修改为   daemonize ...

  9. VS2017与Qt5.7.0(静态库)环境基本配置

    **************************************************************************************************** ...

  10. code1006 等差数列

    我绞尽脑汁想一个更好的算法,然而不能如愿,只好写一个n^3的了 很简单,就是暴力搜索(还好n<100) 先排序,然后循环i=1ton,j=i+1ton 把a[i]a[j]确定为等差数列开始的两个 ...