[BZOJ1977]严格次小生成树
【问题描述】
小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。
正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值)
这下小C蒙了,他找到了你,希望你帮他解决这个问题。
【输入格式】
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点x和点y之间有一条边,边的权值为z。
【输出格式】
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
【输入样例】
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
【输出样例】
11
【数据范围】
数据中无向图无自环;
50% 的数据N≤2 000 M≤3 000;
80% 的数据N≤50 000 M≤100 000;
100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
题解:
要求求严格次小生成树,首先kruskal就无法使用,prim复杂度太高
于是我们用LCA
构造出最小生成树,可知次小生成树肯定是加入某边再删去一边
假设加入(i,j)则有删去生成树上i~j路径最大的边,用倍增维护
但是严格次小没有解决
可以在用倍增维护最大值时,再维护次小值,那么当最大值等于加入边权值时则删去次大边
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lol;
struct Messi
{
lol u,v;
lol dis;
}edge1[];
struct Node
{
lol next,to;
lol dis;
}edge[];
lol num,head[],set[],depth[],Max[][],Max2[][],fa[][],n,m,ans1,ans=2e9;
bool vis[],b[];
bool cmp(Messi a,Messi b)
{
return a.dis<b.dis;
}
void add(lol u,lol v,lol dis)
{
num++;
edge[num].next=head[u];
head[u]=num;
edge[num].to=v;
edge[num].dis=dis;
}
lol find(lol x)
{
if (set[x]!=x) set[x]=find(set[x]);
return set[x];
}
void dfs(lol x,lol dep)
{int i;
vis[x]=;
depth[x]=dep;
for (i=;i<=;i++)
if (dep>(<<i))
{
Max[x][i]=max(Max[x][i-],Max[fa[x][i-]][i-]);
if (Max[x][i-]!=Max[fa[x][i-]][i-]) Max2[x][i]=Max[x][i-]+Max[fa[x][i-]][i-]-Max[x][i];
Max2[x][i]=max(Max2[x][i],max(Max2[x][i-],Max2[fa[x][i-]][i-]));
fa[x][i]=fa[fa[x][i-]][i-];
}
for (i=head[x];i;i=edge[i].next)
{
int v=edge[i].to;
if (vis[v]==)
{
fa[v][]=x;
Max[v][]=edge[i].dis;
dfs(v,dep+);
}
}
}
lol ask(lol x,lol y,lol d)
{int i;
lol s1=,s2=;
if (depth[x]<depth[y]) swap(x,y);
for (i=;i>=;i--)
if ((<<i)<=depth[x]-depth[y])
{
if (s1!=Max[x][i]) s2=max(s2,min(s1,Max[x][i]));
s2=max(s2,Max2[x][i]);
s1=max(s1,Max[x][i]);
x=fa[x][i];
}
if (x==y)
{
if (s1==d&&s2) return d-s2;
else if (s2==) return 2e9;
else if (s1!=d)return d-s1;
}
for (i=;i>=;i--)
{
if ((<<i)<depth[x]&&fa[x][i]!=fa[y][i])
{
if (s1!=Max[x][i]) s2=max(s2,min(s1,Max[x][i]));
s2=max(s2,Max2[x][i]);
s1=max(s1,Max[x][i]);
if (s1!=Max[y][i]) s2=max(s2,min(s1,Max[y][i]));
s2=max(s2,Max2[y][i]);
s1=max(s1,Max[y][i]);
x=fa[x][i];y=fa[y][i];
}
}
if (s1!=Max[x][]) s2=max(s2,min(s1,Max[x][]));
s2=max(s2,Max2[x][]);
s1=max(s1,Max[x][]);
if (s1!=Max[y][]) s2=max(s2,min(s1,Max[y][]));
s2=max(s2,Max2[y][]);
s1=max(s1,Max[y][]);
x=fa[x][];y=fa[y][];
if (s1==d&&s2) return d-s2;
else if (s2==) return 2e9;
else if (s1!=d)return d-s1;
}
int main()
{int i,j,q,opt,x,y;
//freopen("scrip.in","r",stdin);
//freopen("scrip.out","w",stdout);
cin>>n>>m;
for (i=;i<=m;i++)
{
scanf("%d%d%d",&edge1[i].u,&edge1[i].v,&edge1[i].dis);
}
sort(edge1+,edge1+m+,cmp);
for (i=;i<=n;i++)
set[i]=i;
i=;j=;
while (i<=n-&&j<=m)
{
int p=find(edge1[j].u),q=find(edge1[j].v);
if (p!=q)
{
set[p]=q;
i++;
b[j]=;
ans1+=edge1[j].dis;
add(edge1[j].u,edge1[j].v,edge1[j].dis);
add(edge1[j].v,edge1[j].u,edge1[j].dis);
}
j++;
}
if (i<=n-)
{
cout<<"No MST!";
return ;
}
dfs(,);
for (j=;j<=m;j++)
{
if (b[j]==)
{
ans=min(ans,ask(edge1[j].u,edge1[j].v,edge1[j].dis));
}
}
if (ans==2e9)
{
cout<<"No SST!";
return ;
}
cout<<ans+ans1;
}
[BZOJ1977]严格次小生成树的更多相关文章
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
[BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...
- 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)
非严格次小生成树 很简单,先做最小生成树 然后枚举没加入的边加入,替换掉这个环内最大的边 最后取\(min\) 严格次小生成树 还是一样的 可以考虑维护一个严格次大值 最大值和枚举的边相同就替换次大值 ...
- bzoj1977次小生成树(重要)
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #inclu ...
- [BZOJ1977][BeiJing2010组队]次小生成树
题解: 首先要证明一个东西 没有重边的图上 次小生成树由任何一颗最小生成树替换一条边 但是我不会证啊啊啊啊啊啊啊 然后就很简单了 枚举每一条边看看能不能变 但有一个特殊情况就是,他和环上的最大值相等, ...
- 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)
传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...
- bzoj1977 次小生成树
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...
- [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca
Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...
随机推荐
- nyoj 第几是谁
第几是谁? 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 现在有"abcdefghijkl"12个字符,将其按字典序排列,如果给出任意一种排列, ...
- js 获取 最近七天 30天 昨天的方法 -- 转
自己用到了 找了下 先附上原作的链接 http://www.cnblogs.com/songdongdong/p/7251254.html 原谅我窃取你的果实 谢谢你谢谢你 ~ 先附上我自己用到 ...
- HDFS文件读写操作(基础基础超基础)
环境 OS: Ubuntu 16.04 64-Bit JDK: 1.7.0_80 64-Bit Hadoop: 2.6.5 原理 <权威指南>有两张图,下次po上来好好聊一下 实测 读操作 ...
- .NET CORE 框架ABP的代码生成器(ABP Code Power Tools )使用说明文档
前言 各位好,又是一个多月没更新文章了. 原因嘛,大家都懂的,太忙了~ 临近年末,公司的项目.年会的做技术支持,同事朋友聚餐也比较频繁. 当然视频教程也没有继续更新.我的锅~ 但是这个月好歹抽空做了一 ...
- 转:java中Vector的使用
转:https://www.cnblogs.com/zhaoyan001/p/6077492.html Vector 可实现自动增长的对象数组. java.util.vector提供了向量类(vect ...
- javascript实现继承3种方式: 原型继承、借用构造函数继承、组合继承,模拟extends方法继承
javascript中实现继承的三种方式:原型继承.借用构造函数继承.混合继承: /* js当中的继承 js中 构造函数 原型对象 实力对象的关系: 1 构造函数.prototype = 原型对象 2 ...
- Apache设置用户权限(2个域名。一个能访问全部文件,一个只能访问指定文件)
可以利用apache的虚拟主机的配置设置: 2个域名一个是xxxxx.com ,一个是aaaaa.com xxxxx.com配置只访问jpg文件,aaaaa.com可以访问所有文件 <Virtu ...
- Spring(三):Spring整合Hibernate
背景: 本文主要介绍使用spring-framework-4.3.8.RELEASE与hibernate-release-5.2.9.Final项目整合搭建的过程. 开发环境简介: 1).jdk 1. ...
- Thymeleaf3语法详解和实战
Thymeleaf3语法详解 Thymeleaf是Spring boot推荐使用的模版引擎,除此之外常见的还有Freemarker和Jsp.Jsp应该是我们最早接触的模版引擎.而Freemarker工 ...
- 01、NetCore2.0优化之Web服务器 与 IIS解耦
01.NetCore2.0优化之Web服务器 与 IIS解耦 在Asp.Net Core 2.0中,是如何实现跨平台的?不使用IIS了,在linux上的WebServer是什么? ---------- ...