[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 存在多组数 ...
随机推荐
- @RestController使用 接收jso参数 将参数转换为对象
package com.monitor.controller; import org.springframework.http.ResponseEntity; import org.springfra ...
- script放置最佳位置(转载)
html文件是自上而下的执行方式,但引入的css和javascript的顺序有所不同,css引入执行加载时, 程序仍然往下执行,而执行到<script>脚本是则中断线程,待该script脚 ...
- 【原】使用puppeteer爬虫下载Midi文件
The Beatles 乐队的 Midi文件下载地址 puppeteer官方github地址 midi文件爬取示例代码github地址 1.安装npm 参考:安装npm及cnpm(Windows) 修 ...
- Kafka总结的一张图
- java反射对实体类取值和赋值,可以写成通过实体类获取其他元素的数据,很方便哦~~~
项目中需要过滤前面表单页面中传过来的实体类的中的String类型变量的前后空格过滤,由于前几天看过一个其他技术博客的的java反射讲解,非常受益.于是,哈哈哈 public static <T& ...
- 253. Meeting Rooms II 需要多少间会议室
[抄题]: Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],.. ...
- Ubuntu 安装QT5 后编译程序报错: FindQt5Widgets.cmake
安装QT5.4后,需要编译一个C++程序. Cmakelist 有find_package(Qt5Widgets REQUIRED),cmake 报错如下: CMake Error at CMakeL ...
- SQL游标 数据库编程样例
--处理file与folder中的order -- 声明变量 DECLARE @fileid AS INT, @folderid AS INT, @order AS INT, @oldFolderId ...
- Storm+kafka的HelloWorld初体验
从16年4月5号开始学习kafka,后来由于项目需要又涉及到了storm. 经过几天的扫盲,到今天16年4月13日,磕磕碰碰的总算是写了一个kafka+storm的HelloWorld的例子. 为了达 ...
- 设计模式(java的23种设计模式)
转自:leshui http://blog.csdn.net/leshui/article/details/11951 在java版看见了这篇文章,作者以轻松的语言比喻了java的32种模式,有很好的 ...